5

I don't understand why Fn::Sub in this template is not working. I get the following error:

Template contains errors.: Template error: One or more Fn::Sub intrinsic functions don't specify expected arguments. Specify a string as first argument, and an optional second argument to specify a mapping of values to replace in the string

Resources:
  LambdaSubmitJob:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.lambda_handler
      Runtime: python2.7
      Timeout: 10
      Code:
        ZipFile: |
          import json
          import boto3
  LambdaJobStatusPoll:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.lambda_handler
      Runtime: python2.7
      Timeout: 10
      Code:
        ZipFile: |
          import json
          import boto3
  MyStepF:
    Type: 'AWS::StepFunctions::StateMachine'
    Properties:
      DefinitionString: !Sub 
        - |-
          {
            "Comment": "A state machine that submits a Job to AWS Batch and monitors the Job until it completes.",
            "StartAt": "Submit Job",
            "States": {
              "Submit Job": {
                "Type": "Task",
                "Resource": "${Lambda1}",
                "ResultPath": "$.guid",
                "Next": "Wait 30 seconds"
              },
              {
                "Type": "Task",
                "Resource": "${Lambda2}",
                "ResultPath": "$.guid",
                "Next": "Wait 30 seconds"
              }
            }
          }
        - Lambda2: !GetAtt 
            - LambdaSubmitJob
            - Arn
        - Lambda1: !GetAtt 
            - LambdaJobStatusPoll
            - Arn

But if I have only one mapping then it works.

Resources:
  LambdaSubmitJob:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.lambda_handler
      Runtime: python2.7
      Timeout: 10
      Code:
        ZipFile: |
          import json
          import boto3
  LambdaJobStatusPoll:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.lambda_handler
      Runtime: python2.7
      Timeout: 10
      Code:
        ZipFile: |
          import json
          import boto3
  MyStepF:
    Type: 'AWS::StepFunctions::StateMachine'
    Properties:
      DefinitionString: !Sub 
        - |-
          {
            "Comment": "A state machine that submits a Job to AWS Batch and monitors the Job until it completes.",
            "StartAt": "Submit Job",
            "States": {
              "Submit Job": {
                "Type": "Task",
                "Resource": "${Lambda1}",
                "ResultPath": "$.guid",
                "Next": "Wait 30 seconds"
              }
        - Lambda1: !GetAtt 
            - LambdaJobStatusPoll
            - Arn

I am using CloudFormation Designer to validate these two examples.

MLu
  • 23,798
  • 5
  • 54
  • 81
titus
  • 404
  • 6
  • 17

2 Answers2

5

You are giving the Fn::Sub function 3 arguments:

  1. The String
  2. Mapping for Lambda2
  3. Mapping for Lambda1

Move both Mappings to a single list item and it will work (I also used the "dot-notation" for !GetAtt for simplicity but that's optional).

  DefinitionString: !Sub 
    - |-
      {
         [...]
      }
    - Lambda2: !GetAtt LambdaSubmitJob.Arn
      Lambda1: !GetAtt LambdaJobStatusPoll.Arn

Hope that helps :)

MLu
  • 23,798
  • 5
  • 54
  • 81
  • Thank you. I am aware that I'm lacking fundamentals. – titus Dec 17 '18 at 22:21
  • 1
    @titus It's just YAML, not much to do with CloudFormation. You may find this overview of YAML *lists* and *mappings* useful: https://www.tutorialspoint.com/yaml/yaml_collections_and_structures.htm – MLu Dec 17 '18 at 22:26
0

If you are writing a bash script within your metadata, options 1 and 2 in my example code are valid but option 3 is not because "- |" tells the sub intrinsic function to expect another "- |" as shown in option 1, that should provide mapping of values (e.g - {A mapping of some sort}) to replace strings inside {blablabla}. When the second mapping is not found, the error is thrown.

Metadata:
  AWS::CloudFormation::Init:
   files:
   ##### use
    '/dir/subdir':
      content: !Sub
        - |
          {blablabla}
        - {A mapping of some sort}
    ###### or 

    '/dir2/subdir2':
      content: !Sub |
          {blablabla}

    ##### But don't mix like so

    '/dir3/subdir3':
      content: !Sub
        - |
          {blablabla}
crakama
  • 101
  • 1