<commit_before>'use strict';

const parseUrl = require('url').parse;
const Promise = require('bluebird');
const _ = require('lodash');
const yaml = require('js-yaml');
const errors = require('../errors');
const Timeout = errors.Timeout;
const logger = require('../logger');
const utils = require('../utils');
const CONST = require('../constants');
const retry = utils.retry;
const HttpClient = utils.HttpClient;
const config = require('../config');
const NotFound = errors.NotFound;
const BadRequest = errors.BadRequest;

class BoshDirectorClient extends HttpClient {
  constructor() {
    super({
      headers: {
        Accept: 'application/json,text/plain;q=0.9'
      },
      followRedirect: false
    });
    // primaryConfigs - directors supporting lifecycle oprations
    this.primaryConfigs = BoshDirectorClient.getPrimaryConfigs();
    // activePrimary - directors supporting 'create' oprations
    this.activePrimary = BoshDirectorClient.getActivePrimary();
    // oobDirectorConfigs - directors for OutOfBand backup scenario
    this.oobDirectorConfigs = BoshDirectorClient.getOobDirectorConfigs();
    this.cacheLoadInProgress = false;
    this.populateCache();
  }

  clearCache(config) {
    if (config) {
      logger.info('clearing cache for config - ', config.name);
      _.each(this.cache, (value, key) => value === config ? delete this.cache[key] : '');
    } else {
      this.cache = {};
    }
  }

  static getInfrastructure() {
    return BoshDirectorClient.getActivePrimary()[0].infrastructure;
  }

  static getPrimaryConfigs() {
    return _.filter(config.directors, function (director) {
      return director.primary;
    });
  }

  static getActivePrimary() {
    return _.filter(config.directors, function (director) {
      return director.primary && director.support_create;
    });
  }

  static getOobDirectorConfigs() {
    return _.filter(config.directors, function (director) {
      return !director.primary;
    });
  }

  getConfigByName(name) {
    return _.head(_.filter(config.directors, (director) => director.name === name));
  }

  populateCache() {
    logger.info('Loading Bosh DeploymentName cache... current cached deployments:', _.keys(this.cache));
    this.cacheLoadInProgress = true;
    this.clearCache();
    return Promise
      .map(config.directors,
        (directorConfig) => this.getDeploymentsByConfig(directorConfig))
      .finally(() => {
        this.cacheLoadInProgress = false;
        logger.info('Clearing cacheLoadInProgress flag. Bosh DeploymentName cache is loaded.');
        logger.silly('Cached Deployments:', _.keys(this.cache));
      });
  }

  getDeploymentNamesFromCache(boshName, attempt) {
    return Promise.try(() => {
      if (this.cacheLoadInProgress) {
        if (!attempt) {
          attempt = 1;
        } else if (attempt > CONST.BOSH_POLL_MAX_ATTEMPTS) {
          throw errors.Timeout.toManyAttempts(CONST.BOSH_POLL_MAX_ATTEMPTS, new Error('Fetching deployments from Cache is taking too long.'));
        }
        logger.info(`Cache load in progress. GetDeploymentNames will be delayed by 500 ms - current attempt ${attempt}`);
        return Promise.delay(500 * attempt).then(() => this.getDeploymentNamesFromCache(boshName, ++attempt));
      }
      if (boshName) {
        const deploymentNames = [];
        const config = this.getConfigByName(boshName);
        _.each(this.cache, (value, key) => value === config ? deploymentNames.push(key) : '');
        return deploymentNames;
      } else {<commit_msg>Closes issue #47: BoshDirectorClient cache loading has issues in case of errors Description: Catching all errors in populateCache method and then setting the flag this.cacheLoadInProgress to false.<commit_after>'use strict';

const parseUrl = require('url').parse;
const Promise = require('bluebird');
const _ = require('lodash');
const yaml = require('js-yaml');
const errors = require('../errors');
const Timeout = errors.Timeout;
const logger = require('../logger');
const utils = require('../utils');
const CONST = require('../constants');
const retry = utils.retry;
const HttpClient = utils.HttpClient;
const config = require('../config');
const NotFound = errors.NotFound;
const BadRequest = errors.BadRequest;

class BoshDirectorClient extends HttpClient {
  constructor() {
    super({
      headers: {
        Accept: 'application/json,text/plain;q=0.9'
      },
      followRedirect: false
    });
    // primaryConfigs - directors supporting lifecycle oprations
    this.primaryConfigs = BoshDirectorClient.getPrimaryConfigs();
    // activePrimary - directors supporting 'create' oprations
    this.activePrimary = BoshDirectorClient.getActivePrimary();
    // oobDirectorConfigs - directors for OutOfBand backup scenario
    this.oobDirectorConfigs = BoshDirectorClient.getOobDirectorConfigs();
    this.cacheLoadInProgress = false;
    this.populateCache();
  }

  clearCache(config) {
    if (config) {
      logger.info('clearing cache for config - ', config.name);
      _.each(this.cache, (value, key) => value === config ? delete this.cache[key] : '');
    } else {
      this.cache = {};
    }
  }

  static getInfrastructure() {
    return BoshDirectorClient.getActivePrimary()[0].infrastructure;
  }

  static getPrimaryConfigs() {
    return _.filter(config.directors, function (director) {
      return director.primary;
    });
  }

  static getActivePrimary() {
    return _.filter(config.directors, function (director) {
      return director.primary && director.support_create;
    });
  }

  static getOobDirectorConfigs() {
    return _.filter(config.directors, function (director) {
      return !director.primary;
    });
  }

  getConfigByName(name) {
    return _.head(_.filter(config.directors, (director) => director.name === name));
  }

  populateCache() {
    logger.info('Loading Bosh DeploymentName cache... current cached deployments:', _.keys(this.cache));
    this.cacheLoadInProgress = true;
    this.clearCache();
    return Promise
      .map(config.directors,
        (directorConfig) => this.getDeploymentsByConfig(directorConfig))
      .catch(err => {
        logger.error('Error occurred while fetching deployments & populating cache : ', err);
      })
      .finally(() => {
        this.cacheLoadInProgress = false;
        logger.info('Clearing cacheLoadInProgress flag. Bosh DeploymentName cache is loaded.');
        logger.silly('Cached Deployments:', _.keys(this.cache));
      });
  }

  getDeploymentNamesFromCache(boshName, attempt) {
    return Promise.try(() => {
      if (this.cacheLoadInProgress) {
        if (!attempt) {
          attempt = 1;
        } else if (attempt > CONST.BOSH_POLL_MAX_ATTEMPTS) {
          throw errors.Timeout.toManyAttempts(CONST.BOSH_POLL_MAX_ATTEMPTS, new Error('Fetching deployments from Cache is taking too long.'));
        }
        logger.info(`Cache load in progress. GetDeploymentNames will be delayed by 500 ms - current attempt ${attempt}`);
        return Promise.delay(500 * attempt).then(() => this.getDeploymentNamesFromCache(boshName, ++attempt));
      }
      if (boshName) {
        const deploymentNames = [];
        const config = this.getConfigByName(boshName);
        _.each(this.cache, (value, key) => value === config ? deploymentNames.push(key) : '');
        return deploymentNames;
      } else {
{'fraction_non_alphanumeric': 0.1277088728363091, 'fraction_numerical': 0.0029985007496251873, 'mean_word_length': 3.425814234016888, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2243977', 'n_tokens_mistral': 2137, 'n_tokens_neox': 2076, 'n_words': 479}