Repository: serverless/serverless (JavaScript)
Date: 2019-08-08 10:58:20+00:00
Task type: Bug Fix

Issue:
Amazon EventBridge not compatible with partner event sources
<!--
1. If you have a question and not a bug report please ask first at http://forum.serverless.com
2. Please check if an issue already exists. This bug may have already been documented
3. Check out and follow our Guidelines: https://github.com/serverless/serverless/blob/master/CONTRIBUTING.md
4. Fill out the whole template so we have a good overview on the issue
5. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the Issue
6. Please follow the template, otherwise we'll have to ask you to update it
-->

# This is a Bug Report

## Description

When deploying an AWS Lambda that is triggered by Amazon EventBridge using a partner event source (such as segment.com) a CloudFormation error occurs that the event bus cannot be found. This error appears to be caused by the way the event bus ARN is parsed by Serverless, detailed below.

Configuration:

```yaml
# ...
functions:
  # ...
  create-request:
    handler: functions/handler.createRequest
    events:
      - eventBridge:
          eventBus: 'arn:aws:events:us-east-1:XXXXXXXXXXXX:event-bus/aws.partner/segment.com/XXXXXXXXXX'
          pattern:
            source:
              - 'aws.partner/segment.com/XXXXXXXXXX'
            detail:
              event:
                - 'My Event'
              type:
                - 'track'
# ...
```

The deployment error that is displayed in the console is:

```
Failed to create resource. Event bus XXXXXXXXXX does not exist. See details in CloudWatch Log: 2019/08/06/[$LATEST][...].
```

In the current implementation, Serverless parses out the event bus ARN so it only includes the text after the last `/` character. In the case of partner sources, a portion of the ARN is omitted by this approach.

[Current implementation](https://github.com/serverless/serverless/blob/2c1315666a3bd25c6c744cb810b830dd6d248160/lib/plugins/aws/package/compile/events/eventBridge/index.js#L122) added in #6397 [here](https://github.com/serverless/serverless/commit/871b04e238b19bc9c57a9b430685ad157b52b98b#diff-8996f21d004732c3332fe2aeb726f6bbR122):

```javascript
eventBusName = EventBus.split('/').pop();
```

This implementation works for custom event busses formatted as follows:

```
event-bus/<bus_name>
```

However, it is not compatible with event busses from partner sources or any ARN containing additional `/` characters such as the Segment event bus in my example:

```
event-bus/aws.partner/segment.com/XXXXXXXXXX
```

The above ARN path is converted to `event-bus/XXXXXXXXXX` which does not exist.

Similar or dependent issues:

- #6363 - PR #6397 

## Additional Data

- **_Serverless Framework Version you're using_**: v1.49.0
- **_Operating System_**: Mac OS X 10.14.6
- **_Stack Trace_**:
- **_Provider Error messages_**:
- **_Forum Post_**: https://forum.serverless.com/t/amazon-eventbridge-partner-event-sources-error/9011



Issue discussion:
Thanks for opening @trevorrecker :+1:

We're working on a fix for that right now...

Solution patch:
diff --git a/lib/plugins/aws/customResources/resources/eventBridge/lib/utils.js b/lib/plugins/aws/customResources/resources/eventBridge/lib/utils.js
index 862612cb1e6..faa54fe4de1 100644
--- a/lib/plugins/aws/customResources/resources/eventBridge/lib/utils.js
+++ b/lib/plugins/aws/customResources/resources/eventBridge/lib/utils.js
@@ -2,7 +2,7 @@
 
 function getEventBusName(eventBus) {
   if (eventBus && eventBus.startsWith('arn')) {
-    return eventBus.split('/').pop();
+    return eventBus.slice(eventBus.indexOf('/') + 1);
   }
   return eventBus;
 }
diff --git a/lib/plugins/aws/package/compile/events/eventBridge/index.js b/lib/plugins/aws/package/compile/events/eventBridge/index.js
index 57e09e672c2..92336754726 100644
--- a/lib/plugins/aws/package/compile/events/eventBridge/index.js
+++ b/lib/plugins/aws/package/compile/events/eventBridge/index.js
@@ -119,7 +119,7 @@ class AwsCompileEventBridgeEvents {
               if (EventBus) {
                 let eventBusName = EventBus;
                 if (EventBus.startsWith('arn')) {
-                  eventBusName = EventBus.split('/').pop();
+                  eventBusName = EventBus.slice(EventBus.indexOf('/') + 1);
                 }
                 eventBusResource = {
                   'Fn::Join': [


Test patch:
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 48bf115c3db..b17c12fe285 100644
--- a/lib/plugins/aws/package/compile/events/eventBridge/index.test.js
+++ b/lib/plugins/aws/package/compile/events/eventBridge/index.test.js
@@ -346,7 +346,7 @@ describe('AwsCompileEventBridgeEvents', () => {
       );
     });
 
-    it('should create the necessary resources when using an event bus arn', () => {
+    it('should create the necessary resources when using an own event bus arn', () => {
       awsCompileEventBridgeEvents.serverless.service.functions = {
         first: {
           name: 'first',
@@ -485,6 +485,134 @@ describe('AwsCompileEventBridgeEvents', () => {
       );
     });
 
+    it('should create the necessary resources when using a partner event bus arn', () => {
+      awsCompileEventBridgeEvents.serverless.service.functions = {
+        first: {
+          name: 'first',
+          events: [
+            {
+              eventBridge: {
+                eventBus: 'arn:aws:events:us-east-1:12345:event-bus/aws.partner/partner.com/12345',
+                pattern: {
+                  source: ['aws.partner/partner.com/12345'],
+                  detail: {
+                    event: ['My Event'],
+                    type: ['track'],
+                  },
+                },
+              },
+            },
+          ],
+        },
+      };
+
+      return expect(awsCompileEventBridgeEvents.compileEventBridgeEvents()).to.be.fulfilled.then(
+        () => {
+          const {
+            Resources,
+          } = awsCompileEventBridgeEvents.serverless.service.provider.compiledCloudFormationTemplate;
+
+          expect(addCustomResourceToServiceStub).to.have.been.calledOnce;
+          expect(addCustomResourceToServiceStub.args[0][1]).to.equal('eventBridge');
+          expect(addCustomResourceToServiceStub.args[0][2]).to.deep.equal([
+            {
+              Action: ['events:CreateEventBus', 'events:DeleteEventBus'],
+              Effect: 'Allow',
+              Resource: {
+                'Fn::Join': [
+                  ':',
+                  [
+                    'arn:aws:events',
+                    {
+                      Ref: 'AWS::Region',
+                    },
+                    {
+                      Ref: 'AWS::AccountId',
+                    },
+                    'event-bus/aws.partner/partner.com/12345',
+                  ],
+                ],
+              },
+            },
+            {
+              Action: [
+                'events:PutRule',
+                'events:RemoveTargets',
+                'events:PutTargets',
+                'events:DeleteRule',
+              ],
+              Effect: 'Allow',
+              Resource: {
+                'Fn::Join': [
+                  ':',
+                  [
+                    'arn:aws:events',
+                    {
+                      Ref: 'AWS::Region',
+                    },
+                    {
+                      Ref: 'AWS::AccountId',
+                    },
+                    'rule/aws.partner/partner.com/12345/first-rule-1',
+                  ],
+                ],
+              },
+            },
+            {
+              Action: ['lambda:AddPermission', 'lambda:RemovePermission'],
+              Effect: 'Allow',
+              Resource: {
+                'Fn::Join': [
+                  ':',
+                  [
+                    'arn:aws:lambda',
+                    {
+                      Ref: 'AWS::Region',
+                    },
+                    {
+                      Ref: 'AWS::AccountId',
+                    },
+                    'function',
+                    'first',
+                  ],
+                ],
+              },
+            },
+          ]);
+          expect(Resources.FirstCustomEventBridge1).to.deep.equal({
+            Type: 'Custom::EventBridge',
+            Version: 1,
+            DependsOn: [
+              'FirstLambdaFunction',
+              'CustomDashresourceDasheventDashbridgeLambdaFunction',
+            ],
+            Properties: {
+              ServiceToken: {
+                'Fn::GetAtt': ['CustomDashresourceDasheventDashbridgeLambdaFunction', 'Arn'],
+              },
+              FunctionName: 'first',
+              EventBridgeConfig: {
+                EventBus: 'arn:aws:events:us-east-1:12345:event-bus/aws.partner/partner.com/12345',
+                Input: undefined,
+                InputPath: undefined,
+                InputTransformer: undefined,
+                Pattern: {
+                  detail: {
+                    event: ['My Event'],
+                    type: ['track'],
+                  },
+
+                  source: ['aws.partner/partner.com/12345'],
+                },
+                Schedule: undefined,
+                RuleName: 'first-rule-1',
+              },
+            },
+          });
+        }
+      );
+    });
+
     it('should create the necessary resources when using an input configuration', () => {
       awsCompileEventBridgeEvents.serverless.service.functions = {
         first: {