From b53f080a4dfc8439333090d2a177ac0272b6d1fe Mon Sep 17 00:00:00 2001 From: Pavle Portic <62539667+TheEdgeOfCat@users.noreply.github.com> Date: Thu, 30 Jul 2020 13:27:23 +0200 Subject: [PATCH] fix(AWS EventBridge): Fix attaching lambdas to "default" stage (#7995) --- .../compile/events/eventBridge/index.js | 8 ++- .../compile/events/eventBridge/index.test.js | 71 +++++++++++++++++++ .../event-bridge/service/core.js | 8 ++- .../event-bridge/service/serverless.yml | 8 +++ tests/integration-all/event-bridge/tests.js | 12 +++- tests/utils/eventBridge/index.js | 5 ++ 6 files changed, 108 insertions(+), 4 deletions(-) diff --git a/lib/plugins/aws/package/compile/events/eventBridge/index.js b/lib/plugins/aws/package/compile/events/eventBridge/index.js index ce59eb00d13..609bcfcab30 100644 --- a/lib/plugins/aws/package/compile/events/eventBridge/index.js +++ b/lib/plugins/aws/package/compile/events/eventBridge/index.js @@ -147,6 +147,10 @@ class AwsCompileEventBridgeEvents { ], ], }; + const fullRuleName = + eventBusName === 'default' + ? `rule/${RuleName}` + : `rule/${eventBusName}/${RuleName}`; ruleResource = { 'Fn::Join': [ ':', @@ -156,12 +160,12 @@ class AwsCompileEventBridgeEvents { 'events', { Ref: 'AWS::Region' }, { Ref: 'AWS::AccountId' }, - `rule/${eventBusName}/${RuleName}`, + fullRuleName, ], ], }; - if (!eventBusIamRoleStatements.has(eventBusName)) { + if (!eventBusIamRoleStatements.has(eventBusName) && eventBusName !== 'default') { eventBusIamRoleStatements.set(eventBusName, { Effect: 'Allow', Resource: eventBusResource, diff --git a/lib/plugins/aws/package/compile/events/eventBridge/index.test.js b/lib/plugins/aws/package/compile/events/eventBridge/index.test.js index e768f60c44c..cecaaef51d0 100644 --- a/lib/plugins/aws/package/compile/events/eventBridge/index.test.js +++ b/lib/plugins/aws/package/compile/events/eventBridge/index.test.js @@ -4,9 +4,13 @@ const sinon = require('sinon'); const chai = require('chai'); +const BbPromise = require('bluebird'); +const childProcess = BbPromise.promisifyAll(require('child_process')); const proxyquire = require('proxyquire').noCallThru(); const AwsProvider = require('../../../../provider/awsProvider'); const Serverless = require('../../../../../../Serverless'); +const runServerless = require('../../../../../../../tests/utils/run-serverless'); +const fixtures = require('../../../../../../../tests/fixtures'); const { expect } = chai; chai.use(require('sinon-chai')); @@ -1334,3 +1338,70 @@ describe('AwsCompileEventBridgeEvents', () => { }); }); }); + +describe('EventBridgeEvents', () => { + after(() => { + sinon.restore(); + return fixtures.cleanup(); + }); + + describe('when using the default event bus arn', () => { + const functionName = 'foo'; + let cfResources; + let naming; + + before(() => + fixtures + .extend('function', { + functions: { + [functionName]: { + events: [ + { + eventBridge: { + eventBus: 'arn:aws:events:us-east-1:12345:event-bus/default', + schedule: 'rate(10 minutes)', + }, + }, + ], + }, + }, + }) + .then(fixturePath => { + // Prevent `npm install` in custom resource setup + sinon.stub(childProcess, 'execAsync'); + // Stubbing removes bluebird marker, which will result in bluebird crash on repeated + // promisification attempton. Ensure blubird marker to prevent that + childProcess.execAsync.__isPromisified__ = true; + return runServerless({ + cwd: fixturePath, + cliArgs: ['package'], + }); + }) + .then(({ cfTemplate, awsNaming }) => { + ({ Resources: cfResources } = cfTemplate); + naming = awsNaming; + }) + ); + + it('should create the correct execution role', () => { + const roleId = naming.getCustomResourcesRoleLogicalId(); + const executionRolePolicyStatements = + cfResources[roleId].Properties.Policies[0].PolicyDocument.Statement; + expect(executionRolePolicyStatements[0].Action).to.include('events:PutRule'); + expect(executionRolePolicyStatements[0].Resource['Fn::Join'][1]).to.deep.include( + `rule/service-dev-${functionName}-rule-1` + ); + }); + + it('should create the necessary resources', () => { + const normalizedFunctionName = naming.getNormalizedFunctionName(functionName); + const eventBridgeId = naming.getCustomResourceEventBridgeResourceLogicalId( + normalizedFunctionName, + 1 + ); + expect(cfResources[eventBridgeId].Properties.EventBridgeConfig.RuleName).to.equal( + `service-dev-${functionName}-rule-1` + ); + }); + }); +}); diff --git a/tests/integration-all/event-bridge/service/core.js b/tests/integration-all/event-bridge/service/core.js index 921f0765b17..f34605e6a3a 100644 --- a/tests/integration-all/event-bridge/service/core.js +++ b/tests/integration-all/event-bridge/service/core.js @@ -10,6 +10,12 @@ function eventBusDefault(event, context, callback) { return callback(null, event); } +function eventBusDefaultArn(event, context, callback) { + const functionName = 'eventBusDefaultArn'; + log(functionName, JSON.stringify(event)); + return callback(null, event); +} + function eventBusCustom(event, context, callback) { const functionName = 'eventBusCustom'; log(functionName, JSON.stringify(event)); @@ -22,4 +28,4 @@ function eventBusArn(event, context, callback) { return callback(null, event); } -module.exports = { eventBusDefault, eventBusCustom, eventBusArn }; +module.exports = { eventBusDefault, eventBusDefaultArn, eventBusCustom, eventBusArn }; diff --git a/tests/integration-all/event-bridge/service/serverless.yml b/tests/integration-all/event-bridge/service/serverless.yml index 14c8463c860..f3664f76d24 100644 --- a/tests/integration-all/event-bridge/service/serverless.yml +++ b/tests/integration-all/event-bridge/service/serverless.yml @@ -13,6 +13,14 @@ functions: pattern: source: - serverless.test + eventBusDefaultArn: + handler: core.eventBusDefaultArn + events: + - eventBridge: + eventBus: CHANGE_TO_UNIQUE_PER_RUN + pattern: + source: + - serverless.test eventBusCustom: handler: core.eventBusCustom events: diff --git a/tests/integration-all/event-bridge/tests.js b/tests/integration-all/event-bridge/tests.js index a53297e9cbf..40c9e2c2787 100644 --- a/tests/integration-all/event-bridge/tests.js +++ b/tests/integration-all/event-bridge/tests.js @@ -5,7 +5,12 @@ const { expect } = require('chai'); const { getTmpDirPath, readYamlFile, writeYamlFile } = require('../../utils/fs'); const { confirmCloudWatchLogs } = require('../../utils/misc'); -const { createEventBus, putEvents, deleteEventBus } = require('../../utils/eventBridge'); +const { + createEventBus, + putEvents, + deleteEventBus, + describeEventBus, +} = require('../../utils/eventBridge'); const { createTestService, deployService, removeService } = require('../../utils/integration'); const { getMarkers } = require('../shared/utils'); @@ -31,6 +36,10 @@ describe('AWS - Event Bridge Integration Test', function() { before(async () => { tmpDirPath = getTmpDirPath(); console.info(`Temporary path: ${tmpDirPath}`); + + // get default event bus ARN + const defaultEventBusArn = (await describeEventBus('default')).Arn; + const serverlessConfig = await createTestService(tmpDirPath, { templateDir: path.join(__dirname, 'service'), filesToAdd: [path.join(__dirname, '..', 'shared')], @@ -40,6 +49,7 @@ describe('AWS - Event Bridge Integration Test', function() { namedEventBusName = `${config.service}-named-event-bus`; arnEventBusName = `${config.service}-arn-event-bus`; config.functions.eventBusCustom.events[0].eventBridge.eventBus = namedEventBusName; + config.functions.eventBusDefaultArn.events[0].eventBridge.eventBus = defaultEventBusArn; }, }); diff --git a/tests/utils/eventBridge/index.js b/tests/utils/eventBridge/index.js index 5a07e8937c9..9f1866c0350 100644 --- a/tests/utils/eventBridge/index.js +++ b/tests/utils/eventBridge/index.js @@ -10,6 +10,10 @@ function deleteEventBus(name) { return awsRequest('EventBridge', 'deleteEventBus', { Name: name }); } +function describeEventBus(name) { + return awsRequest('EventBridge', 'describeEventBus', { Name: name }); +} + function putEvents(EventBusName, Entries) { Entries.map(entry => (entry.EventBusName = EventBusName)); const params = { @@ -21,5 +25,6 @@ function putEvents(EventBusName, Entries) { module.exports = { createEventBus, deleteEventBus, + describeEventBus, putEvents, };