Kareem
Kareem

Reputation: 571

AWS: cloudformation CommaDelimitedList and manual list not matching

I'm trying to create a cloudformation template that has default values, and I'm running a few !Sub functions to replace imported parameters into the template. However, I am passing a list to a nodejs Lambda function that I need to !Sub before sending it.

The code that I'm writing:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Creating Athena database and tables

Parameters:
  S3DataLocations:
    Type: CommaDelimitedList
    Description: The S3 locations where the logs are read from (Specify 'Use,Default' to inherit defaults)
    Default: Use,Default

Conditions:
  CustomS3DataLocations: !Equals ['Use,Default', !Join [",", !Ref S3DataLocations]]

Resources:
  # Custom resource for running CreateTableFunction, to create databases
  CreateLogTable:
    Type: Custom::CreateLogTable
    Properties:
      ServiceToken: !GetAtt [CreateLogTableFunction, Arn]
      S3DataLocations:
        Fn::If:
          - CustomS3DataLocations
          - !Split
            - ","
            - !Sub
              - s3://${LoggingBucket}/data/ApplicationLogs1/,
                s3://${LoggingBucket}/data/ApplicationLogs2/,
                s3://${LoggingBucket}/data/ApplicationLogs3/
              - { LoggingBucket: !ImportValue Parent-LoggingBucket}
          - !Ref S3DataLocations

If I pass these as a literal external DataTypes parameter s3://logbucket/data/ApplicationLogs1/,s3://logbucket/data/ApplicationLogs2/,s3://logbucket/data/ApplicationLogs3/ it works fine and translates to ["s3://logbucket/data/ApplicationLogs1/","s3://logbucket/data/ApplicationLogs2/","s3://logbucket/data/ApplicationLogs3/"] and is interpreted by the Lambda without issue. The parameter gets parsed through the CommaDelimitedList type and is passed to the Lambda without issue.

The issue arises in that I am trying to create a manual default, so I need to !Sub a list, as a string, then !Split to be passed as an actual list to the Custom Lambda. This doesn't seem to be working every way I try it and I cannot figure why.

I've been inspecting the success (manual param) and failure (defaults, without manual param) and I cant see a big difference. The event of the lambda shows, when working:

{
    "RequestType": "Create",
    "ServiceToken": "hidden",
    "ResponseURL": "hidden",
    "StackId": "hidden",
    "RequestId": "hidden",
    "LogicalResourceId": "CreateLogTable",
    "ResourceType": "Custom::CreateLogTable",
    "ResourceProperties": {
        "S3DataLocations": [
            "s3://loggingbucket/data/ApplicationLogs/",
            "s3://loggingbucket/data/ApplicationLogs/",
            "s3://loggingbucket/data/ApplicationLogs/",
            "s3://loggingbucket/data/ApplicationLogs/"
        ]
    }
}

And when NOT working:

...
{
    "RequestType": "Create",
    "ServiceToken": "hidden",
    "ResponseURL": "hidden",
    "StackId": "hidden",
    "RequestId": "hidden",
    "LogicalResourceId": "CreateLogTable",
    "ResourceType": "Custom::CreateLogTable",
    "ResourceProperties": {
        "S3DataLocations": [
            "s3://logging/data/ApplicationLogs/",
            " s3://loggingbucket/data/ApplicationLogs/",
            " s3://loggingbucket/data/ApplicationLogs/",
            " s3://loggingbucket/data/ApplicationLogs/"
        ]
    }
}

I'm a little stuck here, I think there might be some Type mismatch but I cant tell the difference between the manual and param.

Does anyone have any idea?

Upvotes: 2

Views: 1664

Answers (1)

Marcin
Marcin

Reputation: 238477

You can break your string into multiple line while preventing the change of \n into space using quotation and slash combo.

To verify that, I used the following surrogate template for your situation:


Resources:

  MyBucket:
    Type: AWS::S3::Bucket
    Properties: {}

Outputs:
  Test1:
    Value: !Sub
          - s3://${LoggingBucket}/data/ApplicationLogs1/,
            s3://${LoggingBucket}/data/ApplicationLogs2/,
            s3://${LoggingBucket}/data/ApplicationLogs3/
          - { LoggingBucket: "Parent-LoggingBucket"}

  Test2:
    Value: !Sub
          - "s3://${LoggingBucket}/data/ApplicationLogs1/,\
            s3://${LoggingBucket}/data/ApplicationLogs2/,\
            s3://${LoggingBucket}/data/ApplicationLogs3/"
          - { LoggingBucket: "Parent-LoggingBucket"}   

The Test1 produces string with spaces as in your question:

s3://Parent-LoggingBucket/data/ApplicationLogs1/, s3://Parent-LoggingBucket/data/ApplicationLogs2/, s3://Parent-LoggingBucket/data/ApplicationLogs3/

In contrast, Test2 does not have space:

s3://Parent-LoggingBucket/data/ApplicationLogs1/,s3://Parent-LoggingBucket/data/ApplicationLogs2/,s3://Parent-LoggingBucket/data/ApplicationLogs3/

Upvotes: 1

Related Questions