Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use !FindInMap in !Sub | userdata section

Currently I am converting CFT from JSON to Yaml. Everything works fine until Userdata section.I am having hard time to use any of functions like !Ref or !FindInMap in userdata section.

UserData:

Fn::Base64: !Sub |
        #!/bin/bash -v
        /command {Fn::FindInMap: [ "url", Ref: AWS::Region, Ref: EnvironmentType ] } 

It would be very helpful, If anyone can share any snippet of code.

like image 926
Ramya Krishna Avatar asked Nov 09 '16 11:11

Ramya Krishna


People also ask

What does FN :: sub do?

Short description. You can use the Fn::Sub intrinsic function to substitute supported functions or to substitute variables in an input string with values that you specify.

What is FindInMap in CloudFormation?

The intrinsic function Fn::FindInMap returns the value corresponding to keys in a two-level map that's declared in the Mappings section.

How can cloud formation be used to create a stack based on the template code?

To create a stack you run the aws cloudformation create-stack command. You must provide the stack name, the location of a valid template, and any input parameters. Parameters are separated with a space and the key names are case sensitive.

Which section of the template file can be used to set values based on a region?

The optional Mappings section matches a key to a corresponding set of named values. For example, if you want to set values based on a region, you can create a mapping that uses the region name as a key and contains the values you want to specify for each specific region.


3 Answers

I've been having fun and games with this as well. Although the documentation says that Fn::FindInMap is supported in Fn::Sub, there's no example of use and I've tried all sorts of combinations of quotes and colons without success, but I finally seem to have hit upon a functional solution using mappings. The following should work:

Fn::Base64: !Sub
  - |+
    #!/bin/bash -v
    /command ${Url}
  - Url:
      Fn::FindInMap:
        - UrlMap
        - !Ref AWS::Region
        - !Ref EnvironmentType

The pipe at the start of arg0 tells YAML to preserve newlines, and the plus tells it to keep a newline afterwards. Arg1 tells it to substitute the result of the Fn::FindInMap for the Url in arg0.

The following shorter version should also work:

Fn::Base64: !Sub
  - |+
    #!/bin/bash -v
    /command ${Url}
  - Url:
      Fn::FindInMap: [UrlMap, Ref: "AWS::Region", Ref: EnvironmentType]

But you should test that. Note the commas, quotes, and reversion to Ref:s rather than !Refs. This probably tells us something about how the files are being pre-processed, but I'm not sure what that is.

I'm sure that this solution is obvious to experienced YAMLers, but I was only just starting to get my head around JSON when all this YAMLy goodness was added to CloudFormation.

like image 152
Daniel Ives Avatar answered Nov 07 '22 08:11

Daniel Ives


I had similar use case: Substitute value from map for corresponding parameter value. If parameter value doesn't match the mapping entry, use default value. Here's my working sample, hope this helps.

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  Env:
    Type: String
    Description: The environment.

Mappings:
  envResourcesMap:
    dev:
      someHost: "hostVal_D"
    staging:
      someHost: "hostVal_S"
    prod:
      someHost: "hostVal_P"
    other:
      someHost: "hostValm_XXX"

Conditions:
  IsDevEnv: !Equals
    - !Ref Env
    - dev
  IsStagingEnv: !Equals
    - !Ref Env
    - staging
  IsProdEnv: !Equals
    - !Ref Env
    - prod
  IsStandardEnv:
    Fn::Or:
      - Condition: IsDevEnv
      - Condition: IsStagingEnv
      - Condition: IsProdEnv

Resources:
  storeSSM:
    Type: AWS::SSM::Parameter
    Properties:
      Description: !Sub "DESC for ${Env}"
      Name: !Sub "/Global/ssmpath/someHost"
      Type: String
      Value: !Sub
        - ${spiderman}
        - spiderman: !If [
            IsStandardEnv,
            !FindInMap [ "envResourcesMap", !Ref Env, "someHost" ],
            !FindInMap [ "envResourcesMap", "other", "someHost" ]]
like image 33
user3338953 Avatar answered Nov 07 '22 09:11

user3338953


This works fine for me

UserData :
  Fn::Base64 : !Sub
  - |
    #!/bin/bash -v
    export some_variable = ${url}
  - url : !FindInMap [Mapping, !Ref AWS::Region, !Ref EnvironmentType]
like image 1
Aman Mahajan Avatar answered Nov 07 '22 09:11

Aman Mahajan