All resources placed in Create CF template, can't reference Lambda's get put in Update CF template

It seems that the way serverless splits up the CF template into two (Create and Update json files), this causes issues when the resources reference the entities that are only in the Update stack.

I have noticed that all the resources that I have defined in the yaml file, get put into the Create CF template, as well as the Update CF template. However, all the lambda’s are only in the Update CF template.

This means I can’t deploy, as I have IoT resources which need to reference Lambda ARN’s/

For instance, I have a resource for an IoT rule which needs to be created after the lambda’s have been created, as it references them in it’s definition. I have tried to use a DependsOn statement, but deployment fails as I think it’s only loading the Create CF template first (and the lamdba definition is not in there).

This is the yaml:

    AgentUploadRule:
      Type: AWS::IoT::TopicRule
      DependsOn: "PutAgentDataLambdaFunction"
      Properties:
        TopicRulePayload:
          RuleDisabled: false
          Sql: "SELECT * FROM '${self:service}-heartbeat-${opt:stage}'"
          Actions:
            - Lambda: 
                FunctionArn: "arn:aws:lambda:xxxxx-putAgentData"

Is there any way to force this resource to appear in the update CF template only?

cheers,
Chris.

@str3tch The create stack just creates the S3 bucket for the code packages. The resources you define in serverless.yml are not included in the create stack.

Is that Lambda in the same service? I have gotten this to work without issues by using Fn::GetAttr .

Maybe try this:

AgentUploadRule:
  Type: AWS::IoT::TopicRule
  DependsOn: "PutAgentDataLambdaFunction"
  Properties:
    TopicRulePayload:
      RuleDisabled: false
      Sql: "SELECT * FROM '${self:service}-heartbeat-${opt:stage}'"
      Actions:
        - Lambda: 
            FunctionArn: { Fn::GetAtt: [ PutAgentDataLambdaFunction, Arn ] }

hey @johncmckim, it’s definitely in the create stack. Along with everything else in my resources section.

here’s a screenshot:

Hey @johncmckim, I am trying the Fn::GetAttr, what value do you put in there? I’m presuming it has to be the logical name of the lambda as specified in the CF template, not the lamdba name given in the yaml file?

For instance, instead of “putAgentData”, I specify “PutAgentDataLambdaFunction” - is that what you do?

However, I still can’t get it to work as all resources are in the create CF template and I think it tries to resolve the create before the update… and it fails

Serverless Error ---------------------------------------                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                             
     Template error: instance of Fn::GetAtt references undefined                                                                                                                                                                                                             
     resource PutAgentDataLambdaFunction" 

OK the ugly workaround I’ve had to do is temporarily remove the resources from the yaml file, so only lambda’s are present.

Then deploy. This creates the lambda’s

Then I re-add the resources, but making sure I manually create the lambda references using Fn::Join, as the Fn::GetAtt does not work), and deploy again

   AgentUploadRule:
      Type: AWS::IoT::TopicRule
      # DependsOn: "PutAgentDataLambdaFunction"
      Properties:
        TopicRulePayload:
          RuleDisabled: false
          Sql: "SELECT * FROM '${self:service}-heartbeat-${opt:stage}'"
          Actions:
            - Lambda: 
                FunctionArn:
                  Fn::Join :
                  - ""
                  - - "arn:aws:lambda:${self:provider.region}:"
                    - Ref : "AWS::AccountId"
                    - ":function:${self:service}-putAgentData-${opt:stage}"

This works because the first deploy created the lambdas, which can now be referenced by the second deploy. However it’s an ugly workaround and cutting and pasting code is not great at all.

Is there something I’m missing? Is there a better way to be able to reference lambda’s in the resources?

cheers,
Chris.

@str3tch This is a bug that was introduced and is currently getting resolved. The resources should only be in the update template, not in the create template. PR to fix this: https://github.com/serverless/serverless/pull/2385

We’re also introducing more stringent testing in our main repo and including our integration test suite there now to make sure things like this NEVER break again.

ahhh @flomotlik thank you!! I thought I was going crazy.

pretty shocking bug that slipped through, but glad it’s being fixed… when is the next NPM release of serverless planned? there’s a few things that need fixing up I think.

We’ll do the release as soon as this bug is fixed, probably later this week. We’re also introducing more testing and processes to make sure that doesn’t slip through any more.

1 Like