Repository: serverless/serverless (JavaScript)
Date: 2017-08-14 06:02:13+00:00
Task type: Bug Fix

Issue:
Unresolved resource dependencies when using Fn::ImportValue for role in function with kinesis event handler
# This is a Bug Report

## Description

When I have a AWS service with a function that defines both a kinesis stream endpoint and a role  a cloudformation import (using Fn::ImportValue) I receive the following error:

```
The CloudFormation template is invalid: Template format error: Unresolved resource dependencies [IamRoleLambdaExecution] in the Resources block of the template
```

My Function Role is defined using:
```
role: 
   Fn::ImportValue: Dev-Shared-Lambda-Resources-ExtendedLambdaRoleArn
```

In the generated template I can see that a dependency to the default role has been generated for the Kinesis mapping:

```    "PostingsEventSourceMappingKinesisDevSharedKinesisResourcesPostingsKinesisStreamArn": {
      "Type": "AWS::Lambda::EventSourceMapping",
      "DependsOn": "IamRoleLambdaExecution"
}
```

The issue appears to be the code in: `/Users/toby.hede/src/serverless/lib/plugins/aws/package/compile/events/stream/index.js`
at around line 125.

I should be able to use the `Fn::ImportValue` function to reference a role when using a kinesis event handler. 

We have a group of  resources that a couple of services share, and imports are useful for managing these dependencies.

I have another service using a role via `Fn::ImportValue` that does not have a kinesis stream and this works ok. The bad dependency is just in the event mapping for kinesis.

## Additional Data

* ***Serverless Framework Version you're using***: 1.19.0 and master
* ***Operating System***: OSX
* ***Stack Trace***:
```
➜  service-postings git:(master) ✗ SLS_DEBUG=true AWS_PROFILE=r1-dev sls deploy --stage th --kinesis-env dev
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Configurating CloudWatch log retention
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Validating template...

  Error --------------------------------------------------

  The CloudFormation template is invalid: Template format error: Unresolved resource dependencies [IamRoleLambdaExecution] in the Resources block of the template

     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

  Stack Trace --------------------------------------------

Error: The CloudFormation template is invalid: Template format error: Unresolved resource dependencies [IamRoleLambdaExecution] in the Resources block of the template
    at provider.request.catch (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/lib/validateTemplate.js:25:13)
From previous event:
    at AwsDeploy.validateTemplate (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/lib/validateTemplate.js:20:12)
From previous event:
    at AwsDeploy.BbPromise.bind.then (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:117:39)
From previous event:
    at Object.aws:deploy:deploy:validateTemplate [as hook] (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:113:10)
    at BbPromise.reduce (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:236:55)
From previous event:
    at PluginManager.invoke (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:236:22)
    at PluginManager.spawn (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:248:17)
    at AwsDeploy.BbPromise.bind.then (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:91:48)
From previous event:
    at Object.deploy:deploy [as hook] (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:87:10)
    at BbPromise.reduce (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:236:55)
From previous event:
    at PluginManager.invoke (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:236:22)
    at PluginManager.run (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:255:17)
    at variables.populateService.then (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/Serverless.js:99:33)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
From previous event:
    at Serverless.run (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/Serverless.js:86:74)
    at serverless.init.then (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/bin/serverless:39:50)
```

My function is defined using the following serverless.yml declaration:

```
  postings:
    handler: postings/handler.main
    role:
      Fn::ImportValue: Dev-Shared-Lambda-Resources-ExtendedLambdaRoleArn
    events:
      - stream:
          type: kinesis
          arn:
            Fn::ImportValue: Dev-Shared-Kinesis-Resources-PostingsKinesisStreamArn
```
Unresolved resource dependencies when using Fn::ImportValue for role in function with kinesis event handler
# This is a Bug Report

## Description

When I have a AWS service with a function that defines both a kinesis stream endpoint and a role  a cloudformation import (using Fn::ImportValue) I receive the following error:

```
The CloudFormation template is invalid: Template format error: Unresolved resource dependencies [IamRoleLambdaExecution] in the Resources block of the template
```

My Function Role is defined using:
```
role: 
   Fn::ImportValue: Dev-Shared-Lambda-Resources-ExtendedLambdaRoleArn
```

In the generated template I can see that a dependency to the default role has been generated for the Kinesis mapping:

```    "PostingsEventSourceMappingKinesisDevSharedKinesisResourcesPostingsKinesisStreamArn": {
      "Type": "AWS::Lambda::EventSourceMapping",
      "DependsOn": "IamRoleLambdaExecution"
}
```

The issue appears to be the code in: `/Users/toby.hede/src/serverless/lib/plugins/aws/package/compile/events/stream/index.js`
at around line 125.

I should be able to use the `Fn::ImportValue` function to reference a role when using a kinesis event handler. 

We have a group of  resources that a couple of services share, and imports are useful for managing these dependencies.

I have another service using a role via `Fn::ImportValue` that does not have a kinesis stream and this works ok. The bad dependency is just in the event mapping for kinesis.

## Additional Data

* ***Serverless Framework Version you're using***: 1.19.0 and master
* ***Operating System***: OSX
* ***Stack Trace***:
```
➜  service-postings git:(master) ✗ SLS_DEBUG=true AWS_PROFILE=r1-dev sls deploy --stage th --kinesis-env dev
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Configurating CloudWatch log retention
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Validating template...

  Error --------------------------------------------------

  The CloudFormation template is invalid: Template format error: Unresolved resource dependencies [IamRoleLambdaExecution] in the Resources block of the template

     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

  Stack Trace --------------------------------------------

Error: The CloudFormation template is invalid: Template format error: Unresolved resource dependencies [IamRoleLambdaExecution] in the Resources block of the template
    at provider.request.catch (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/lib/validateTemplate.js:25:13)
From previous event:
    at AwsDeploy.validateTemplate (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/lib/validateTemplate.js:20:12)
From previous event:
    at AwsDeploy.BbPromise.bind.then (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:117:39)
From previous event:
    at Object.aws:deploy:deploy:validateTemplate [as hook] (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:113:10)
    at BbPromise.reduce (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:236:55)
From previous event:
    at PluginManager.invoke (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:236:22)
    at PluginManager.spawn (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:248:17)
    at AwsDeploy.BbPromise.bind.then (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:91:48)
From previous event:
    at Object.deploy:deploy [as hook] (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/plugins/aws/deploy/index.js:87:10)
    at BbPromise.reduce (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:236:55)
From previous event:
    at PluginManager.invoke (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:236:22)
    at PluginManager.run (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/classes/PluginManager.js:255:17)
    at variables.populateService.then (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/Serverless.js:99:33)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
From previous event:
    at Serverless.run (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/lib/Serverless.js:86:74)
    at serverless.init.then (/Users/toby.hede/.nvm/versions/node/v7.10.0/lib/node_modules/serverless/bin/serverless:39:50)
```

My function is defined using the following serverless.yml declaration:

```
  postings:
    handler: postings/handler.main
    role:
      Fn::ImportValue: Dev-Shared-Lambda-Resources-ExtendedLambdaRoleArn
    events:
      - stream:
          type: kinesis
          arn:
            Fn::ImportValue: Dev-Shared-Kinesis-Resources-PostingsKinesisStreamArn
```


Issue discussion:

Solution patch:
diff --git a/lib/plugins/aws/package/compile/events/stream/index.js b/lib/plugins/aws/package/compile/events/stream/index.js
index 695d88f18f8..61820a09445 100644
--- a/lib/plugins/aws/package/compile/events/stream/index.js
+++ b/lib/plugins/aws/package/compile/events/stream/index.js
@@ -136,6 +136,11 @@ class AwsCompileStreamEvents {
                 funcRole['Fn::GetAtt'][1] === 'Arn'
               ) {
                 dependsOn = `"${funcRole['Fn::GetAtt'][0]}"`;
+              } else if ( // otherwise, check if we have an import
+                typeof funcRole === 'object' &&
+                'Fn::ImportValue' in funcRole
+              ) {
+                dependsOn = '[]';
               } else if (typeof funcRole === 'string') {
                 dependsOn = `"${funcRole}"`;
               }


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 d3b455df06c..1571bab4ed8 100644
--- a/lib/plugins/aws/package/compile/events/stream/index.test.js
+++ b/lib/plugins/aws/package/compile/events/stream/index.test.js
@@ -217,6 +217,31 @@ describe('AwsCompileStreamEvents', () => {
       ).to.equal(null);
     });
 
+    it('should not throw error if IAM role is imported', () => {
+      awsCompileStreamEvents.serverless.service.functions = {
+        first: {
+          role: { 'Fn::ImportValue': 'ExportedRoleId' },
+          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.length).to.equal(0);
+      expect(awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate
+        .Resources.IamRoleLambdaExecution).to.equal(null);
+    });
+
+
     it('should not throw error if custom IAM role reference is set in provider', () => {
       const roleLogicalId = 'RoleLogicalId';
       awsCompileStreamEvents.serverless.service.functions = {