Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
ecs-publish / lib / elb-manager.js
Size: Mime:
'use strict';
const ELBv2 = require('aws-sdk/clients/elbv2'),
  logger = require('./logger');

function checkIfTargetGroupExists ({cfg}) {
  logger.action(`Checking if target group exists...`);
  const elb = new ELBv2({ region: cfg.region });
  return elb.describeTargetGroups({ Names: [cfg.fullName] }).promise()
    .then((data) => {
      cfg.targetGroupArn = data.TargetGroups[0].TargetGroupArn;
      logger.result(`${cfg.targetGroupArn}`);
      return {cfg, status: 'EXISTS'};
    })
    .catch((err) => {
      if (err.code !== 'TargetGroupNotFound') throw err;
      logger.result('Does not exist.');
      return {cfg, status: 'DOESNOTEXIST'};
    });
}

function checkIfTargetGoupIsInLoadBalancer ({cfg}) {
  logger.action(`Checking if target group is in load balancer...`);
  const elb = new ELBv2({ region: cfg.region });
  return elb.describeListeners({ LoadBalancerArn: cfg.loadBalancerArn }).promise()
    .then((data) => {
      cfg.listeners = data.Listeners;
      cfg.service.listenerPorts.forEach((port) => {
        if (cfg.listeners.filter((listener) => { return listener.Port === port; }).length !== 1) throw new Error(`Load balancer ${cfg.service.loadBalancer} is missing a listener for port ${port}`);
      });
      return Promise.all(data.Listeners.map((listener) => {
        return elb.describeRules({ ListenerArn: listener.ListenerArn }).promise();
      }));
    })
    .then((rulePromises) => {
      return new Promise((resolve, reject) => {
        cfg.rules = [];
        rulePromises.forEach((rp, i) => {
          const rules = rp.Rules.map((rule) => {
            rule.ListenerArn = cfg.listeners[i].ListenerArn;
            return rule;
          });
          cfg.rules = cfg.rules.concat(rules);
        });
        let rules = [];
        cfg.rules.forEach((rule) => {
          const matchingRules = rule.Actions.filter((action) => { return action.TargetGroupArn === cfg.targetGroupArn; });
          if (matchingRules.length > 0) {
            logger.result(rule.RuleArn);
            rules.push(rule);
          }
        });
        if (rules.length > 0) return resolve({cfg, rules});
        return reject(new Error('ListenerRuleNotFoundException'));
      });
    });
}

module.exports.ensureTargetGroupExists = function ({cfg}) {
  if (!cfg.targetGroup) return {cfg};
  return checkIfTargetGroupExists({cfg})
    .then(({cfg, status}) => {
      if (status === 'EXISTS') return {cfg};
      logger.action('Creating target group...');
      const elb = new ELBv2({ region: cfg.region });
      const tg = cfg.targetGroup;
      return elb.createTargetGroup({
        Name: cfg.fullName,
        VpcId: tg.VpcId,
        Port: tg.Port,
        Protocol: tg.Protocol || 'HTTP',
        HealthCheckIntervalSeconds: tg.HealthCheckIntervalSeconds || '0',
        HealthCheckPath: tg.HealthCheckPath || '/',
        HealthCheckPort: tg.HealthCheckPort || 'traffic-port',
        HealthCheckProtocol: tg.HealthCheckProtocol || 'HTTP',
        HealthCheckTimeoutSeconds: tg.HealthCheckTimeoutSeconds || '5',
        HealthyThresholdCount: tg.HealthyThresholdCount || '2',
        UnhealthyThresholdCount: tg.UnhealthyThresholdCount || '3',
        Matcher: tg.Matcher || { HttpCode: '200' },
        TargetType: (cfg.service.networkConfiguration) ? 'ip' : 'instance'
      }).promise()
        .then((data) => {
          cfg.targetGroupArn = data.TargetGroups[0].TargetGroupArn;
          logger.result(`${cfg.targetGroupArn}`);
          return {cfg};
        });
    });
};

module.exports.updateTargetGroupAttributes = function ({cfg}) {
  if (!cfg.targetGroup || !cfg.targetGroup.Attributes) return {cfg};
  logger.action(`Updating target group attributes...`);
  const elb = new ELBv2({ region: cfg.region });
  return elb.modifyTargetGroupAttributes({
    TargetGroupArn: cfg.targetGroupArn,
    Attributes: cfg.targetGroup.Attributes
  }).promise()
    .then((data) => {
      logger.result(`Done`);
      return {cfg};
    });
};

module.exports.ensureLoadBalancerExists = function ({cfg}) {
  if (!cfg.targetGroup || !cfg.service || !cfg.service.loadBalancer) return {cfg};
  logger.action(`Ensuring load balancer '${cfg.service.loadBalancer}' exists...`);
  const elb = new ELBv2({ region: cfg.region });
  return elb.describeLoadBalancers({ Names: [cfg.service.loadBalancer] }).promise()
    .then((data) => {
      if (data.LoadBalancers.length !== 1) throw new Error(`load balancer ${cfg.service.loadBalance} does not exist`);
      cfg.loadBalancerArn = data.LoadBalancers[0].LoadBalancerArn;
      cfg.loadBalancerDnsName = data.LoadBalancers[0].DNSName;
      logger.result(`${cfg.loadBalancerArn}`);
      return {cfg};
    });
};

module.exports.ensureTargetGroupIsInLoadBalancer = function ({cfg}) {
  if (!cfg.targetGroup || !cfg.service || !cfg.service.loadBalancer) return {cfg};
  return checkIfTargetGoupIsInLoadBalancer({cfg})
    .catch((err) => {
      if (err.message !== 'ListenerRuleNotFoundException') throw new Error(`${err.code}: ${err.message}`);
      const elb = new ELBv2({ region: cfg.region });
      logger.result('Listener rules mismatch for target group.');
      logger.action('Creating rules for each listener...');
      return Promise.all(cfg.service.listenerPorts.map((port) => {
        const listener = cfg.listeners.filter((listener) => { return listener.Port === port; })[0];
        const existingPriorities = cfg.rules.filter((rule) => { return rule.ListenerArn === listener.ListenerArn; }).map((r) => { return (r.Priority !== 'default') ? parseInt(r.Priority) : -1; });
        const params = {
          Actions: [
            {
              TargetGroupArn: cfg.targetGroupArn,
              Type: 'forward'
            }
          ],
          Conditions: [
            {
              Field: 'host-header',
              Values: [cfg.hostHeader]
            }
          ],
          ListenerArn: listener.ListenerArn,
          Priority: Math.max.apply(null, existingPriorities) + 1
        };
        return elb.createRule(params).promise()
          .then((data) => {
            logger.result(`Port ${port}: ${data.Rules[0].RuleArn}`);
          });
      }))
        .then(() => {
          return {cfg};
        });
    });
};

module.exports.confirmTargetGroupExists = function ({cfg}) {
  return checkIfTargetGroupExists({cfg});
};

module.exports.deleteTargetGroupFromLoadBalancer = function ({cfg}) {
  if (!cfg.targetGroup || !cfg.service || !cfg.service.loadBalancer) return {cfg};
  return checkIfTargetGoupIsInLoadBalancer({cfg})
    .then(({cfg, rules}) => {
      logger.action('Deleting rules from listeners...');
      const elb = new ELBv2({ region: cfg.region });
      return Promise.all(rules.map((rule) => { return elb.deleteRule({ RuleArn: rule.RuleArn }).promise(); }))
        .then((datas) => {
          logger.result('Done');
          return {cfg};
        });
    })
    .catch((err) => {
      if (err.message !== 'ListenerRuleNotFoundException') throw new Error(`${err.code}: ${err.message}`);
      logger.result('No listener rules found for target group');
      return {cfg};
    });
};

module.exports.deleteTargetGroup = function ({cfg}) {
  if (!cfg.targetGroup) return {cfg};
  return checkIfTargetGroupExists({cfg})
    .then(({cfg, status}) => {
      if (status === 'DOESNOTEXIST') return {cfg};
      logger.action('Deleting target group...');
      const elb = new ELBv2({ region: cfg.region });
      return elb.deleteTargetGroup({ TargetGroupArn: cfg.targetGroupArn }).promise()
        .then((data) => {
          logger.result('Done');
          return {cfg};
        });
    });
};

module.exports.ensureCertificateIsInLoadBalancer = function ({cfg}) {
  if (!cfg.targetGroup || !cfg.service || !cfg.service.loadBalancer) return {cfg};
  logger.action('Ensuring certificate is in load balancer...');
  if (!cfg.certificateArn) throw new Error('Certificate not issued.');
  const httpsListeners = cfg.listeners.filter((listener) => { return listener.Port === 443; });
  if (httpsListeners.length !== 1) throw new Error('No HTTPS listener');
  const elb = new ELBv2({ region: cfg.region });
  return elb.addListenerCertificates({
    Certificates: [{ CertificateArn: cfg.certificateArn }],
    ListenerArn: httpsListeners[0].ListenerArn
  }).promise()
    .then((data) => {
      logger.result('Done');
      return {cfg};
    });
};