Repository: serverless/serverless (JavaScript) — Bug Fix

Issue:
Serverless fails to deploy service with a kinesis stream event: Unresolved resource dependencies [IamPolicyLambdaExecution] in the Resources block of the template
<!--
1. If you have a question and not a bug/feature request please ask it at http://forum.serverless.com
2. Please check if an issue already exists so there are no duplicates
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

We were trying to deploy service that would read from a Kinesis stream and the deployment failed with the following message:

`Template format error: Unresolved resource dependencies
     [IamPolicyLambdaExecution] in the Resources block of
     the template`

I am including my serverless.yml for reference:

```
provider:
  name: aws
  runtime: python2.7
  region: ap-southeast-1
  role: testKinesisStream

functions:
  hello:
    handler: handler.hello
    events:
      - 
        stream:
          arn: "arn:aws:kinesis:ap-southeast-1:XXXXXXXXXXX:stream/StreamTest"
          batchSize: 100
          startingPosition: LATEST
          enabled: false

resources:
  Resources:
    testKinesisStream:
      Type: AWS::IAM::Role
      Properties:
        RoleName: test-kinesis-stream-dev-role
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: "Allow"
              Principal:
                Service:
                  - "lambda.amazonaws.com"
              Action: "sts:AssumeRole"
        Policies:
          - PolicyName: test-kinesis-stream-dev-policy
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: "Allow"
                  Action:
                    - "kinesis:DescribeStream"
                    - "kinesis:GetShardIterator"
                    - "kinesis:GetRecords"
                    - "kinesis:ListStreams"
                  Resource: "arn:aws:kinesis:ap-southeast-1:XXXXXXXXXXX:stream/StreamTest"
```

## Additional Data

* ***Serverless Framework Version you're using***: 1.4.0
* ***Operating System***: darwin
* ***Provider Error messages***: `Template format error: Unresolved resource dependencies
     [IamPolicyLambdaExecution] in the Resources block of
     the template`



Discussion:
Hey @aashish004 thanks for reporting.

We're currently working on fixes for the stream support in those PRs here:

- https://github.com/serverless/serverless/pull/3111
- https://github.com/serverless/serverless/pull/3083
- https://github.com/serverless/serverless/pull/3141

Those will be merged the upcoming days (hopefully) 👍  They should resolve the problem you're currently facing
Is this going to be resolved anytime soon?
@aashish004 thanks for getting back.

Could you please try that again with the new Serverless version?

We've pushed some fixes in the last couple of weeks regarding those kind of issues...
Still got the same problem using the following setup: 
```
Your Environment Information -----------------------------

OS:                 darwin

Node Version:       4.3.2

Serverless Version: 1.9.0
```


Configuration:


```
dev-1-events-checkin-store:
    name: ${opt:stage, self:provider.stage}-${opt:version, self:provider.version}-${file(env.yml):environment.namespace_events_checkin}-store
    handler: functions/${file(env.yml):environment.namespace_events_checkin}-store/index.handler
    role: storeRole
    package:
      include:
        - functions/${file(env.yml):environment.namespace_events_checkin}-store/**
    environment:
      FLIGHTSUPPORT_FIREHOSE_STREAM: ${opt:stage, self:provider.stage}-${file(env.yml):environment.namespace_events_checkin}
    events:
      - stream:
          arn: arn:aws:kinesis:${opt:region, self:provider.region}:${opt:accountId, self:provider.accountId}:stream/${opt:stage, self:provider.stage}-${file(env.yml):environment.namespace_events_checkin}
          batchSize: 1
          startingPosition: LATEST
          enabled: true
```

```
resources:
  Resources:
    storeRole:
      Type: AWS::IAM::Role
      Properties:
        Path: /
        RoleName: ${opt:stage, self:provider.stage}-${file(env.yml):environment.namespace_events_checkin}-store-role
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - lambda.amazonaws.com
                  - apigateway.amazonaws.com
              Action: sts:AssumeRole
        Policies:
          - PolicyName: ${opt:stage, self:provider.stage}-${file(env.yml):environment.namespace_events_checkin}-store-kinesis-policy
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: Allow
                  Action:
                    - kinesis:GetRecords
                    - kinesis:GetShardIterator
                    - kinesis:DescribeStream
                    - kinesis:ListStreams
                  Resource: "arn:aws:kinesis:${opt:region, self:provider.region}:*:*"
```


I'm also seeing this issue.  Looking into it I can see DependsOn is not being filled out correctly in the compiled CF for a particular case when a custom role defined.

 OK if I submit a PR for a proposed fix?  

Resolving patch:
diff --git a/lib/plugins/aws/package/compile/events/stream/index.js b/lib/plugins/aws/package/compile/events/stream/index.js
index a0bb4ab366b..695d88f18f8 100644
--- a/lib/plugins/aws/package/compile/events/stream/index.js
+++ b/lib/plugins/aws/package/compile/events/stream/index.js
@@ -136,6 +136,8 @@ class AwsCompileStreamEvents {
                 funcRole['Fn::GetAtt'][1] === 'Arn'
               ) {
                 dependsOn = `"${funcRole['Fn::GetAtt'][0]}"`;
+              } else if (typeof funcRole === 'string') {
+                dependsOn = `"${funcRole}"`;
               }
             }
             const streamTemplate = `


Test patch:
diff --git a/lib/plugins/aws/package/compile/events/stream/index.test.js b/lib/plugins/aws/package/compile/events/stream/index.test.js
index 0ebc32de75e..d3b455df06c 100644
--- a/lib/plugins/aws/package/compile/events/stream/index.test.js
+++ b/lib/plugins/aws/package/compile/events/stream/index.test.js
@@ -136,6 +136,31 @@ describe('AwsCompileStreamEvents', () => {
       ).to.equal(null);
     });
 
+    it('should not throw error if custom IAM role name reference is set in function', () => {
+      const roleLogicalId = 'RoleLogicalId';
+      awsCompileStreamEvents.serverless.service.functions = {
+        first: {
+          role: roleLogicalId,
+          events: [
+            {
+              // doesn't matter if DynamoDB or Kinesis stream
+              stream: 'arn:aws:dynamodb:region:account:table/foo/stream/1',
+            },
+          ],
+        },
+      };
+
+      // pretend that the default IamRoleLambdaExecution is not in place
+      awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate
+        .Resources.IamRoleLambdaExecution = null;
+
+      expect(() => { awsCompileStreamEvents.compileStreamEvents(); }).to.not.throw(Error);
+      expect(awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate
+        .Resources.FirstEventSourceMappingDynamodbFoo.DependsOn).to.equal(roleLogicalId);
+      expect(awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate
+        .Resources.IamRoleLambdaExecution).to.equal(null);
+    });
+
     it('should not throw error if custom IAM role reference is set in function', () => {
       const roleLogicalId = 'RoleLogicalId';
       awsCompileStreamEvents.serverless.service.functions = {
@@ -219,6 +244,33 @@ describe('AwsCompileStreamEvents', () => {
         .Resources.IamRoleLambdaExecution).to.equal(null);
     });
 
+    it('should not throw error if custom IAM role name reference is set in provider', () => {
+      const roleLogicalId = 'RoleLogicalId';
+      awsCompileStreamEvents.serverless.service.functions = {
+        first: {
+          events: [
+            {
+              // doesn't matter if DynamoDB or Kinesis stream
+              stream: 'arn:aws:dynamodb:region:account:table/foo/stream/1',
+            },
+          ],
+        },
+      };
+
+      // pretend that the default IamRoleLambdaExecution is not in place
+      awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate
+        .Resources.IamRoleLambdaExecution = null;
+
+      awsCompileStreamEvents.serverless.service.provider
+        .role = roleLogicalId;
+
+      expect(() => { awsCompileStreamEvents.compileStreamEvents(); }).to.not.throw(Error);
+      expect(awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate
+        .Resources.FirstEventSourceMappingDynamodbFoo.DependsOn).to.equal(roleLogicalId);
+      expect(awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate
+        .Resources.IamRoleLambdaExecution).to.equal(null);
+    });
+
     describe('when a DynamoDB stream ARN is given', () => {
       it('should create event source mappings when a DynamoDB stream ARN is given', () => {
         awsCompileStreamEvents.serverless.service.functions = {