diff --git a/__tests__/index.test.js b/__tests__/index.test.js index 580b6f99..9b148be9 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -247,7 +247,7 @@ describe('ServerlessVpcPlugin', () => { mockHelper('EC2', 'describeImages', mockCallback); - const actual = await plugin.getImagesByName('test'); + const actual = await plugin.getImagesByName('test', 'test', 'test'); expect(actual).toEqual(['ami-test']); expect(mockCallback).toHaveBeenCalled(); expect.assertions(3); diff --git a/__tests__/nat_instance.test.js b/__tests__/nat_instance.test.js index a3d2cb6d..bd618518 100644 --- a/__tests__/nat_instance.test.js +++ b/__tests__/nat_instance.test.js @@ -121,7 +121,68 @@ describe('nat_instance', () => { const imageId = 'ami-00a9d4a05375b2763'; - const actual = buildNatInstance(imageId, ['us-east-1a', 'us-east-1b']); + const actual = buildNatInstance(imageId, 't2.micro', ['us-east-1a', 'us-east-1b']); + expect(actual).toEqual(expected); + expect.assertions(1); + }); + }); + + describe('#buildNatInstance createNatInstanceFckNat', () => { + it('builds an EC2 instance', () => { + const expected = { + NatInstance: { + Type: 'AWS::EC2::Instance', + DependsOn: 'InternetGatewayAttachment', + Properties: { + AvailabilityZone: { + 'Fn::Select': ['0', ['us-east-1a', 'us-east-1b']], + }, + BlockDeviceMappings: [ + { + DeviceName: '/dev/xvda', + Ebs: { + VolumeSize: 10, + VolumeType: 'gp2', + DeleteOnTermination: true, + }, + }, + ], + ImageId: 'ami-0d30a34832b46dcae', + InstanceType: 't4g.nano', + Monitoring: false, + NetworkInterfaces: [ + { + AssociatePublicIpAddress: true, + DeleteOnTermination: true, + Description: 'eth0', + DeviceIndex: '0', + GroupSet: [ + { + Ref: 'NatSecurityGroup', + }, + ], + SubnetId: { + Ref: 'PublicSubnet1', + }, + }, + ], + SourceDestCheck: false, + Tags: [ + { + Key: 'Name', + Value: { + // eslint-disable-next-line no-template-curly-in-string + 'Fn::Sub': '${AWS::StackName}-nat', + }, + }, + ], + }, + }, + }; + + const imageId = 'ami-0d30a34832b46dcae'; + + const actual = buildNatInstance(imageId, 't4g.nano', ['us-east-1a', 'us-east-1b']); expect(actual).toEqual(expected); expect.assertions(1); }); diff --git a/src/index.js b/src/index.js index 8c24d626..803103e8 100644 --- a/src/index.js +++ b/src/index.js @@ -43,6 +43,7 @@ class ServerlessVpcPlugin { let createDbSubnet = true; let createFlowLogs = false; let createNatInstance = false; + let createNatInstanceFckNat = false; let createBastionHost = false; let createParameters = false; let bastionHostKeyName = null; @@ -103,6 +104,12 @@ class ServerlessVpcPlugin { if ('createNatInstance' in vpcConfig && typeof vpcConfig.createNatInstance === 'boolean') { ({ createNatInstance } = vpcConfig); + if ( + 'createNatInstanceFckNat' in vpcConfig && + typeof vpcConfig.createNatInstanceFckNat === 'boolean' + ) { + ({ createNatInstanceFckNat } = vpcConfig); + } } if (createNatGateway && createNatInstance) { @@ -162,10 +169,15 @@ class ServerlessVpcPlugin { const resources = providerObj.compiledCloudFormationTemplate.Resources; let vpcNatAmi = null; + let instanceType = null; if (createNatInstance) { this.serverless.cli.log('Finding latest VPC NAT Instance AMI...'); - const images = await this.getImagesByName('amzn-ami-vpc-nat*'); + instanceType = createNatInstanceFckNat ? 't4g.nano' : 't2.micro'; + const images = createNatInstanceFckNat + ? await this.getImagesByName('568608671756', 'fck-nat-amzn2-*', 'arm64') + : await this.getImagesByName('amazon', 'amzn-ami-vpc-nat*', 'x86_64'); + if (Array.isArray(images) && images.length > 0) { [vpcNatAmi] = images; } else { @@ -204,7 +216,11 @@ class ServerlessVpcPlugin { if (createNatInstance && vpcNatAmi) { this.serverless.cli.log(`Provisioning NAT Instance using AMI ${vpcNatAmi}`); - Object.assign(resources, buildNatSecurityGroup(), buildNatInstance(vpcNatAmi, zones)); + Object.assign( + resources, + buildNatSecurityGroup(), + buildNatInstance(vpcNatAmi, instanceType, zones), + ); } if (createBastionHost) { @@ -374,16 +390,18 @@ class ServerlessVpcPlugin { /** * Return an array of AMI images which match the VPC NAT Instance image * + * @param {String} owner AMI id to search for * @param {String} name AMI name to search for + * @param {String} arch AMI architecture to search for * @return {Array} */ - async getImagesByName(name) { + async getImagesByName(owner, name, arch) { const params = { - Owners: ['amazon'], + Owners: [owner], Filters: [ { Name: 'architecture', - Values: ['x86_64'], + Values: [arch], }, { Name: 'image-type', diff --git a/src/nat_instance.js b/src/nat_instance.js index 17371ea3..31c1033f 100644 --- a/src/nat_instance.js +++ b/src/nat_instance.js @@ -68,11 +68,12 @@ function buildNatSecurityGroup() { * Build the NAT instance * * @param {Object} imageId AMI image ID + * @param {String} instance type * @param {Array} zones Array of availability zones * @param {Object} params * @return {Object} */ -function buildNatInstance(imageId, zones = [], { name = 'NatInstance' } = {}) { +function buildNatInstance(imageId, instanceType, zones = [], { name = 'NatInstance' } = {}) { if (!imageId) { return {}; } @@ -99,7 +100,7 @@ function buildNatInstance(imageId, zones = [], { name = 'NatInstance' } = {}) { }, ], ImageId: imageId, // amzn-ami-vpc-nat-hvm-2018.03.0.20181116-x86_64-ebs - InstanceType: 't2.micro', + InstanceType: instanceType, Monitoring: false, NetworkInterfaces: [ {