frankthelen/cloudmonkey

View on GitHub
src/services/EC2.js

Summary

Maintainability
D
1 day
Test Coverage
const assert = require('assert');
const AWS = require('aws-sdk');
const Service = require('../Service');

class EC2 extends Service {
  constructor({ region, alias } = {}) {
    super({ name: 'ec2', alias });
    assert(region, '"region" is required');
    this.aws = new AWS.EC2({ apiVersion: '2016-11-15', region });
    this.registerResourceTypes();
  }

  registerResourceTypes() {
    this.register({
      name: 'instance',
      list: async () => this.loadResources('instance'),
      filters: {
        id: (item, value) => item.InstanceId === value,
        vpc: (item, value) => item.VpcId === value,
      },
      identity: item => item.InstanceId,
      travel: {
        subnet: async (instances) => {
          const snIds = instances.map(instance => instance.SubnetId);
          const sns = await this.loadResources('subnet');
          return sns.filter(sn => snIds.includes(sn.SubnetId));
        },
        securityGroup: async (instances) => {
          const sgIds = instances // eslint-disable-next-line max-len
            .reduce((acc, instance) => [...acc, ...instance.SecurityGroups.map(sg => sg.GroupId)], []);
          const sgs = await this.loadResources('securityGroup');
          return sgs.filter(sg => sgIds.includes(sg.GroupId));
        },
      },
    });
    this.register({
      name: 'internetGateway',
      list: async () => this.loadResources('internetGateway'),
      filters: {
        id: (item, value) => item.InternetGatewayId === value,
        vpc: (item, value) => item.Attachments.filter(att => att.VpcId === value).length,
      },
      identity: item => item.InternetGatewayId,
      travel: {
        routeTable: async (igws) => {
          const igwIds = igws.map(igw => igw.InternetGatewayId);
          const rts = await this.loadResources('routeTable');
          return rts.filter(rt => rt.Routes
            .filter(route => igwIds.includes(route.GatewayId)).length);
        },
      },
    });
    this.register({
      name: 'routeTable',
      list: async () => this.loadResources('routeTable'),
      filters: {
        id: (item, value) => item.RouteTableId === value,
        vpc: (item, value) => item.VpcId === value,
      },
      identity: item => item.RouteTableId,
      travel: {
        subnet: async (rts) => {
          const snIds = rts
            .reduce((acc, rt) => [...acc, ...rt.Associations.map(a => a.SubnetId)], []);
          const sns = await this.loadResources('subnet');
          return sns.filter(sn => snIds.includes(sn.SubnetId));
        },
      },
    });
    this.register({
      name: 'securityGroup',
      list: async () => this.loadResources('securityGroup'),
      filters: {
        id: (item, value) => item.GroupId === value,
        name: (item, value) => item.GroupName === value,
        vpc: (item, value) => item.VpcId === value,
      },
      identity: item => item.GroupId,
    });
    this.register({
      name: 'subnet',
      list: async () => this.loadResources('subnet'),
      filters: {
        id: (item, value) => item.SubnetId === value,
        vpc: (item, value) => item.VpcId === value,
      },
      identity: item => item.SubnetId,
      travel: {
        instance: async (sns) => {
          const snIds = sns.map(sn => sn.SubnetId);
          const instances = await this.loadResources('instance');
          return instances.filter(instance => snIds.includes(instance.SubnetId));
        }
      },
    });
  }

  async loadResources(resourceType) {
    if (!this.cache) {
      this.cache = {};
    }
    if (this.cache[resourceType]) {
      return this.cache[resourceType];
    }
    let list;
    if (resourceType === 'instance') {
      const params = { MaxResults: 1000 }; // TODO: paging
      const data = await this.aws.describeInstances(params).promise();
      list = data.Reservations.reduce((acc, res) => [...acc, ...res.Instances], []);
    } else if (resourceType === 'internetGateway') {
      const params = {};
      const data = await this.aws.describeInternetGateways(params).promise();
      list = data.InternetGateways;
    } else if (resourceType === 'routeTable') {
      const params = {};
      const data = await this.aws.describeRouteTables(params).promise();
      list = data.RouteTables;
    } else if (resourceType === 'securityGroup') {
      const params = { MaxResults: 1000 }; // TODO: paging
      const data = await this.aws.describeSecurityGroups(params).promise();
      list = data.SecurityGroups;
    } else if (resourceType === 'subnet') {
      const params = {};
      const data = await this.aws.describeSubnets(params).promise();
      list = data.Subnets;
    }
    this.cache[resourceType] = list;
    return list;
  }
}

module.exports = EC2;