diff --git a/lib/plugins/aws/package/compile/events/msk/index.js b/lib/plugins/aws/package/compile/events/msk/index.js index 25e77407d1ad..3737d4fc1b72 100644 --- a/lib/plugins/aws/package/compile/events/msk/index.js +++ b/lib/plugins/aws/package/compile/events/msk/index.js @@ -1,7 +1,5 @@ 'use strict'; -const _ = require('lodash'); - class AwsCompileMSKEvents { constructor(serverless) { this.serverless = serverless; @@ -15,11 +13,15 @@ class AwsCompileMSKEvents { type: 'object', properties: { arn: { - // TODO: Add possiblity to use Fn::ImportValue and Ref - type: 'string', - // TODO: Should it be even more detailed? - pattern: - '^arn:aws[a-zA-Z-]*:kafka:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-[1-9]{1}:[0-9]{12}:cluster', + oneOf: [ + { + type: 'string', + pattern: + '^arn:aws[a-zA-Z-]*:kafka:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-[1-9]{1}:[0-9]{12}:cluster', + }, + { $ref: '#/definitions/awsCfImport' }, + { $ref: '#/definitions/awsCfRef' }, + ], }, batchSize: { type: 'number', @@ -42,7 +44,6 @@ class AwsCompileMSKEvents { }); } - // TODO: Copied from sqs/stream - see if it can be refactored resolveDependsOn(funcRole) { let dependsOn = 'IamRoleLambdaExecution'; @@ -79,7 +80,6 @@ class AwsCompileMSKEvents { } getMSKClusterName(eventSourceArn) { - // TODO: EVALUATE IF THIS WORKS PROPERLY if (eventSourceArn['Fn::ImportValue']) { return eventSourceArn['Fn::ImportValue']; } else if (eventSourceArn.Ref) { @@ -89,7 +89,6 @@ class AwsCompileMSKEvents { return eventSourceArn.split('/')[1]; } - // TODO: Add documentation compileMSKEvents() { this.serverless.service.getAllFunctions().forEach(functionName => { const functionObj = this.serverless.service.getFunction(functionName); @@ -156,8 +155,7 @@ class AwsCompileMSKEvents { [mskEventLogicalId]: mskResource, }; - // TODO: Potentially replace _merge with Object.assign - _.merge(cfTemplate.Resources, newMSKObject); + Object.assign(cfTemplate.Resources, newMSKObject); } }); diff --git a/lib/plugins/aws/package/compile/events/msk/index.test.js b/lib/plugins/aws/package/compile/events/msk/index.test.js index 840faad9477f..386c0bfb8e2f 100644 --- a/lib/plugins/aws/package/compile/events/msk/index.test.js +++ b/lib/plugins/aws/package/compile/events/msk/index.test.js @@ -1,17 +1,15 @@ 'use strict'; +const chai = require('chai'); +const runServerless = require('../../../../../../../test/utils/run-serverless'); +const fixtures = require('../../../../../../../test/fixtures'); const AwsCompileMSKEvents = require('./index'); const Serverless = require('../../../../../../Serverless'); const AwsProvider = require('../../../../provider/awsProvider'); -const chai = require('chai'); -chai.use(require('chai-as-promised')); -chai.use(require('sinon-chai')); +const { expect } = chai; -const expect = chai.expect; - -const runServerless = require('../../../../../../../tests/utils/run-serverless'); -const fixtures = require('../../../../../../../tests/fixtures'); +chai.use(require('chai-as-promised')); describe('AwsCompileMSKEvents', () => { after(fixtures.cleanup); @@ -49,14 +47,14 @@ describe('AwsCompileMSKEvents', () => { eventSourceMappingResource = cfTemplate.Resources[ naming.getMSKEventLogicalId('foo', 'ClusterName', 'TestingTopic') - ].Properties; + ]; defaultIamRole = cfTemplate.Resources.IamRoleLambdaExecution; }) ) ); - it('should correctly compile EventSourceMapping resource', () => { - expect(eventSourceMappingResource).to.deep.equal({ + it('should correctly compile EventSourceMapping resource properties', () => { + expect(eventSourceMappingResource.Properties).to.deep.equal({ BatchSize: 100, Enabled: true, EventSourceArn: arn, @@ -90,6 +88,10 @@ describe('AwsCompileMSKEvents', () => { Resource: '*', }); }); + + it('should correctly compile EventSourceMapping resource DependsOn ', () => { + expect(eventSourceMappingResource.DependsOn).to.equal('IamRoleLambdaExecution'); + }); }); describe('when using all parameters', () => { @@ -124,8 +126,8 @@ describe('AwsCompileMSKEvents', () => { const resource = cfTemplate.Resources[ awsNaming.getMSKEventLogicalId('foo', 'ClusterName', 'TestingTopic') - ].Properties; - expect(resource).to.deep.equal({ + ]; + expect(resource.Properties).to.deep.equal({ BatchSize: batchSize, Enabled: enabled, EventSourceArn: arn, @@ -139,6 +141,35 @@ describe('AwsCompileMSKEvents', () => { ); }); }); + + describe('when no msk events are defined', () => { + it('should not modify the default IAM role', () => { + return runServerless({ + cwd: fixtures.map.function, + cliArgs: ['package'], + }).then(({ cfTemplate }) => { + const defaultIamRole = cfTemplate.Resources.IamRoleLambdaExecution; + expect(defaultIamRole.Properties.Policies[0].PolicyDocument.Statement).not.to.deep.include({ + Effect: 'Allow', + Action: ['kafka:DescribeCluster', 'kafka:GetBootstrapBrokers'], + Resource: [], + }); + + expect(defaultIamRole.Properties.Policies[0].PolicyDocument.Statement).not.to.deep.include({ + Effect: 'Allow', + Action: [ + 'ec2:CreateNetworkInterface', + 'ec2:DescribeNetworkInterfaces', + 'ec2:DescribeVpcs', + 'ec2:DeleteNetworkInterface', + 'ec2:DescribeSubnets', + 'ec2:DescribeSecurityGroups', + ], + Resource: '*', + }); + }); + }); + }); }); describe('getMSKClusterName', () => { @@ -169,3 +200,43 @@ describe('getMSKClusterName', () => { expect(result).to.equal('ReferencedResource'); }); }); + +describe('resolveDependsOn', () => { + let awsCompileMSKEvents; + + before(() => { + const serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); + awsCompileMSKEvents = new AwsCompileMSKEvents(serverless); + }); + + it('with ARN', () => { + const funcRole = 'arn:aws:iam::xxxxxxxxxxxx:role/xxxx'; + const result = awsCompileMSKEvents.resolveDependsOn(funcRole); + expect(result).to.deep.equal([]); + }); + + it('with string', () => { + const funcRole = 'role'; + const result = awsCompileMSKEvents.resolveDependsOn(funcRole); + expect(result).to.equal(funcRole); + }); + + it('with Fn::ImportValue', () => { + const funcRole = { 'Fn::ImportValue': 'importvalue' }; + const result = awsCompileMSKEvents.resolveDependsOn(funcRole); + expect(result).to.deep.equal([]); + }); + + it('with Ref', () => { + const funcRole = { Ref: 'ReferencedResource' }; + const result = awsCompileMSKEvents.resolveDependsOn(funcRole); + expect(result).to.deep.equal([]); + }); + + it('with Fn::GetAtt reference to role ARN', () => { + const funcRole = { 'Fn::GetAtt': ['Resource', 'Arn'] }; + const result = awsCompileMSKEvents.resolveDependsOn(funcRole); + expect(result).to.equal('Resource'); + }); +});