Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Fn::Join" with delimiter from a parameter?

I'm trying to parametise the delimiter used by an Fn::Join, e.g. at first I had:

"Name" : { "Fn::Join" : [ ".", [ 
           { "Ref":"serviceName"}, { "Ref": "environment" } ] ] },

Which works well, but then I changed it to:

"Name" : { "Fn::Join" : [ {"Ref":"HostNameSeparator"}, [
           { "Ref":"serviceName"}, { "Ref": "environment" } ] ] },

I get the following error from the validation phase:

A client error (ValidationError) occurred when calling the
ValidateTemplate operation: Template error: every Fn::Join object
requires two parameters, (1) a string delimiter and (2) a list of
strings to be joined or a function that returns a list of strings
(such as Fn::GetAZs) to be joined.

Is it possible to do what I want, i.e. pass the Join delimiter as a template parameter?

(I've shortened the examples above for clarity sake, please ignore typos)

like image 687
Amos Shapira Avatar asked Nov 01 '22 06:11

Amos Shapira


1 Answers

You can achieve this by using a CustomResource. This CloudFormation Template is ready to run and illustrates how it could work. Delimiter is passed as a parameter and you'll find the joined string in the Outputs of the stack.

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Example Join",
    "Parameters": {
        "Delimiter": {
            "Type": "String"
        }
    },
    "Resources": {
        "LambdaExecutionRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": ["lambda.amazonaws.com"]
                            },
                            "Action": ["sts:AssumeRole"]
                        }
                    ]
                },
                "Path": "/",
                "Policies": [
                    {
                        "PolicyName": "root",
                        "PolicyDocument": {
                            "Version": "2012-10-17",
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "logs:CreateLogGroup",
                                        "logs:CreateLogStream",
                                        "logs:PutLogEvents"
                                    ],
                                    "Resource": "arn:aws:logs:*:*:*"
                                },
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "cloudformation:DescribeStacks"
                                    ],
                                    "Resource": "*"
                                }
                            ]
                        }
                    }
                ]
            }
        },
        "LambdaJoin": {
            "Type": "AWS::Lambda::Function",
            "Properties": {
                "Code": {
                    "ZipFile":  { "Fn::Join": ["\n", [
                        "var response = require('cfn-response');\n",
                        "exports.handler = function (event, context) {\n",
                        "if (event.RequestType === 'Delete') {\n",
                        "return response.send(event, context, response.SUCCESS, {}, event.PhysicalResourceId);\n",
                        "}\n",
                        "var delimiter = event.ResourceProperties.delimiter || '';\n",
                        "var strings = event.ResourceProperties.strings || [];\n",
                        "return response.send(event, context, response.SUCCESS, { string: strings.join(delimiter) }, event.PhysicalResourceId);\n",
                        "};\n"
                    ]]}
                },
                "Handler": "index.handler",
                "Runtime": "nodejs",
                "Timeout": "10",
                "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }
            }
        },
        "CustomJoin": {
            "Type": "Custom::Join",
            "Version": "1.0",
            "Properties": {
                "ServiceToken": { "Fn::GetAtt": ["LambdaJoin", "Arn"] },
                "delimiter": { "Ref": "Delimiter" },
                "strings": ["first", "second", "third"]
            },
            "DependsOn": ["LambdaJoin"]
        }
    },
    "Outputs": {
        "JoinedString": {
            "Value": { "Fn::GetAtt": ["CustomJoin", "string"] }
        }
    }
}
like image 103
Carl Avatar answered Nov 13 '22 22:11

Carl