Brian Sidebotham
Brian Sidebotham

Reputation: 1906

Using Fn::Sub with a common string in a Cloud Formation Template

I'm struggling a little with Fn::Sub and Fn::FindInMap in order to create a dynamic value for a resource.

I would like something in the mapping like

Mappings:
  Mapping01:
    common:
      SyncName: "archive-uploader-${AWS::Region}-synchronisation-a2"

Then I'd like to use it something like

Name: !Sub !FindInMap [Mapping01, common, SyncName]

Which I know I can't do because the Sub function cannot take intrinsic functions at the String parameter. But I cannot see a neat way to do this. At the moment I just use Sub and the hardcoded string where I need it.

I'd prefer to have a single place for the string and then use it with Sub where I need it. How can I do that in a CFT?

I don't want to have a large map that just varies the name's region. That's what most of the documentation shows.

Upvotes: 2

Views: 2517

Answers (3)

Chux Uzoeto
Chux Uzoeto

Reputation: 1404

This is fairly straightforward to do. You would need the advanced form of Fn::Sub

First though:

  • if this string will remain same for all regions, you should make the common name a parameter, not a mapping.
  • if it will change per region, then create 2 parameters to hold the b4 and after strings .. I have assumed this is your use case, in my example below
Parameters:
  String1:
    Type: String
    Default: "archive-uploader-"
  String2:
    Type: String
    Default: "-synchronisation-a2"

Resources:

Name:
  Fn::Sub:
    - "${str1}${reg}${str2}${finmap}"  #these are just placeholder formats
    - str1: !Ref String1
      reg: !Ref AWS::Region
      str2: !Ref String2
      finmap: !FindInMap [MapName, MapRootKey, MapValueKey]

  • I hope I read your needs correctly, but in general you can then mix values coming from dynamic vars, from parameters and even from some mappings .. as required.
  • You could probably do same with !Join but it may be more convoluted

Upvotes: 1

I think you could build it up in pieces a little differently and avoid a per-region map. Wouldn't something like this work?

Mappings:
  Mapping01:
    common:
      SyncName: synchronisation-a2

...

Resources:
  MyResource:
    Type: AWS::whatever
    Properties:
      Name: !Sub
        - "archive-uploader-{region}-{suffix}"
        - region: !Ref AWS::Region
          suffix: !FindInMap [Mapping01, common, SyncName]

Upvotes: 0

Marcin
Marcin

Reputation: 238497

As you pointed out you can't do this in plain CFN. Your only options to work around this is through development of CFN macro or custom resource.

Alternative is simply not to use CFN, there are far superior IaC tools (terraform, AWS CDK), pre-process all templates before applying them, or keep hardcoding these values in your templates.

Upvotes: 1

Related Questions