From f300429c8665d0c6da5db7191405f5b3a5f24710 Mon Sep 17 00:00:00 2001 From: TaeSeong Park Date: Tue, 4 Jun 2019 02:59:30 +0900 Subject: [PATCH] Added 'subnetGroup' option (#65) --- README.md | 7 +++++++ __tests__/subnet_groups.test.js | 29 +++++++++++++++++++++++++++++ src/index.js | 17 +++++++++++++++-- src/subnet_groups.js | 20 +++++++++++++++++++- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 506b1c52..a5821850 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,13 @@ custom: services: - kms - secretsmanager + + # optional + # can pick one of subnet groups in (rds / redshift / elasticache / dax) + # By default, if not specified, all of the subnet groups will be created. + # ex) DAX is not available in ap-northeast-2 so I don't want to make DAX subnet group + subnetGroups: + - rds ``` ## CloudFormation Outputs diff --git a/__tests__/subnet_groups.test.js b/__tests__/subnet_groups.test.js index b8c887b2..cecedee9 100644 --- a/__tests__/subnet_groups.test.js +++ b/__tests__/subnet_groups.test.js @@ -3,9 +3,12 @@ const { buildElastiCacheSubnetGroup, buildRedshiftSubnetGroup, buildDAXSubnetGroup, + buildSubnetGroups, } = require('../src/subnet_groups'); describe('subnet_groups', () => { + let subnetGroupList = {}; + describe('#buildRDSSubnetGroup', () => { it('skips building an RDS subnet group with no zones', () => { const actual = buildRDSSubnetGroup(); @@ -35,6 +38,7 @@ describe('subnet_groups', () => { }, }, }; + subnetGroupList.rds = expected; const actual = buildRDSSubnetGroup(2); expect(actual).toEqual(expected); expect.assertions(1); @@ -99,6 +103,7 @@ describe('subnet_groups', () => { }, }, }; + subnetGroupList.elasticache = expected; const actual = buildElastiCacheSubnetGroup(2); expect(actual).toEqual(expected); expect.assertions(1); @@ -160,6 +165,7 @@ describe('subnet_groups', () => { }, }, }; + subnetGroupList.redshift = expected; const actual = buildRedshiftSubnetGroup(2); expect(actual).toEqual(expected); expect.assertions(1); @@ -221,6 +227,7 @@ describe('subnet_groups', () => { }, }, }; + subnetGroupList.dax = expected; const actual = buildDAXSubnetGroup(2); expect(actual).toEqual(expected); expect.assertions(1); @@ -255,4 +262,26 @@ describe('subnet_groups', () => { expect.assertions(1); }); }); + + describe('#buildSubnetGroups', () => { + it('no subnetGroups option', () => { + const expected = Object.keys(subnetGroupList).reduce( + (acc, key) => Object.assign(acc, subnetGroupList[key]), + {}, + ); + const actual = buildSubnetGroups(2, []); + expect(actual).toEqual(expected); + expect.assertions(1); + }); + it('get specific subnetGroups option', () => { + const getSubnetGroupsOptions = ['rds', 'redshift']; + const expected = getSubnetGroupsOptions.reduce( + (acc, key) => Object.assign(acc, subnetGroupList[key]), + {}, + ); + const actual = buildSubnetGroups(2, getSubnetGroupsOptions); + expect(actual).toEqual(expected); + expect.assertions(1); + }); + }); }); diff --git a/src/index.js b/src/index.js index 9abb6a95..31111e88 100644 --- a/src/index.js +++ b/src/index.js @@ -8,7 +8,7 @@ const { buildLambdaSecurityGroup, } = require('./vpc'); const { buildAppNetworkAcl, buildPublicNetworkAcl, buildDBNetworkAcl } = require('./nacl'); -const { buildSubnetGroups } = require('./subnet_groups'); +const { buildSubnetGroups, validSubnetGroups } = require('./subnet_groups'); const { buildEndpointServices, buildLambdaVPCEndpointSecurityGroup } = require('./vpce'); const { buildLogBucket, buildLogBucketPolicy, buildVpcFlowLogs } = require('./flow_logs'); const { buildBastion } = require('./bastion'); @@ -38,6 +38,7 @@ class ServerlessVpcPlugin { let createNatInstance = false; let createBastionHost = false; let bastionHostKeyName = null; + let subnetGroups = []; const { vpcConfig } = this.serverless.service.custom; @@ -70,6 +71,9 @@ class ServerlessVpcPlugin { if (Array.isArray(vpcConfig.services)) { services = vpcConfig.services.map(s => s.trim().toLowerCase()); } + if (Array.isArray(vpcConfig.subnetGroups) && vpcConfig.subnetGroups.length > 0) { + ({ subnetGroups } = vpcConfig); + } if ('createDbSubnet' in vpcConfig && typeof vpcConfig.createDbSubnet === 'boolean') { ({ createDbSubnet } = vpcConfig); @@ -222,7 +226,16 @@ class ServerlessVpcPlugin { if (numZones < 2) { this.serverless.cli.log('WARNING: less than 2 AZs; skipping subnet group provisioning'); } else { - Object.assign(resources, buildSubnetGroups(numZones)); + for (let i = 0; i < subnetGroups.length; i += 1) { + const subnetGrp = subnetGroups[i]; + if (validSubnetGroups.indexOf(subnetGrp) === -1) { + throw new this.serverless.classes.Error( + `WARNING: '${subnetGrp}' is invalid subnetGroups option. + you should input among these options: ['rds', 'redshift', 'elasticache', 'dax']`, + ); + } + } + Object.assign(resources, buildSubnetGroups(numZones, subnetGroups)); } } diff --git a/src/subnet_groups.js b/src/subnet_groups.js index 58f8dbb5..be6489a8 100644 --- a/src/subnet_groups.js +++ b/src/subnet_groups.js @@ -1,5 +1,7 @@ const { DB_SUBNET } = require('./constants'); +const validSubnetGroups = ['rds', 'redshift', 'elasticache', 'dax']; + /** * Build an RDSubnetGroup for a given number of zones * @@ -133,12 +135,27 @@ function buildDAXSubnetGroup(numZones = 0, { name = 'DAXSubnetGroup' } = {}) { * Build the database subnet groups * * @param {Number} numZones Number of availability zones + * @param {Array} subnetGroups options of subnet groups * @return {Object} */ -function buildSubnetGroups(numZones = 0) { +function buildSubnetGroups(numZones = 0, subnetGroups = []) { if (numZones < 2) { return {}; } + const subnetGroupList = { + rds: buildRDSSubnetGroup, + redshift: buildRedshiftSubnetGroup, + elasticache: buildElastiCacheSubnetGroup, + dax: buildDAXSubnetGroup, + }; + function assembleSubnetGrp(acc, service) { + const builtSubnetGroup = subnetGroupList[service.toLowerCase()](numZones); + return Object.assign(acc, builtSubnetGroup); + } + + if (subnetGroups.length > 0) { + return subnetGroups.reduce(assembleSubnetGrp, {}); + } return Object.assign( {}, buildRDSSubnetGroup(numZones), @@ -154,4 +171,5 @@ module.exports = { buildRDSSubnetGroup, buildRedshiftSubnetGroup, buildSubnetGroups, + validSubnetGroups, };