Intrinsic functions¶
cfnrain adds some intrinsic functions that CloudFormation does not have. cfnrain resolves them when it packages the template, so CloudFormation never sees them. It also simplifies Fn::Join and Fn::Select when it can.
| Function | Short form | Where it works |
|---|---|---|
Fn::Merge |
!Merge |
In module resources |
Fn::InsertFile |
!InsertFile |
Anywhere |
Fn::Invoke |
!Invoke |
In a template that has a Modules section |
Fn::Merge only runs in modules
In the resources of the parent template, cfnrain leaves Fn::Merge as it is. CloudFormation has no Fn::Merge, so a deploy with Fn::Merge outside a module fails.
Fn::Merge¶
Fn::Merge merges a list of maps into one map, or a list of lists into one list. For maps, a later key replaces an earlier one. For lists, cfnrain joins the lists and keeps duplicates.
Use it to combine values that come from module properties, such as tags from the parent and tags from the module.
The module:
Parameters:
X:
Type: Object
Y:
Type: Object
XX:
Type: List
YY:
Type: List
Resources:
Bar:
Type: A::B::C
Properties:
Merged:
Fn::Merge:
- !Ref X
- !Ref Y
Lists:
Fn::Merge:
- !Ref XX
- !Ref YY
- !Ref YY
The parent template:
Modules:
Foo:
Source: merge-module.yaml
Properties:
X:
A: "BBB"
B: "c"
Y:
B: "CCC"
C: "D"
XX:
- a
- b
YY:
- b
- c
The packaged template:
Resources:
FooBar:
Type: A::B::C
Properties:
Merged:
A: BBB
B: CCC
C: D
Lists:
- a
- b
- b
- c
- b
- c
Fn::InsertFile¶
Fn::InsertFile <path> inserts the contents of a file as a string. The path is relative to the template. Unlike !Rain::Embed, it keeps the whitespace at the end of the file.
The template:
insertfile-file.yaml:
The packaged template:
Fn::Invoke¶
Fn::Invoke calls a module like a function. It takes three items:
- The name of a module in the
Modulessection - A map of properties. These replace the properties that the
Modulessection sets. - The name of a module output
cfnrain evaluates the module with the new properties and inserts the output. A module for Invoke does not need resources. Parameters and Outputs are enough. A common use is a naming module that joins an environment, an application and a resource name.
The naming module, invoke-module.yaml:
Description: This module outputs a consistent resource name
Parameters:
Env:
Type: String
Description: The environment, for example, dev, stage, prod
App:
Type: String
Description: The application name
Name:
Type: String
Description: The name of the resource
Delimiter:
Type: String
Default: "-"
MaxLength:
Type: Integer
Description: If the components exceed this, truncate and append a hash
IncludeRegion:
Type: Boolean
Default: false
IncludeAccount:
Type: Boolean
Default: false
LabelOrder:
Type: List<String>
Default:
- Name
- App
- Env
- Region
- Account
Conditions:
IncludeRegion:
Fn::Equals:
- !Ref IncludeRegion
- true
Resources:
Why:
Type: X::Y::Z
Properties:
Id:
Fn::Join:
- !Ref Delimiter
- - !Ref Name
- !Ref App
- !Ref Env
- Fn::If:
- IncludeRegion
- !Ref AWS::Region
- !Ref AWS::NoValue
Outputs:
Id:
Value:
Fn::Join:
- !Ref Delimiter
- - !Ref Name
- !Ref App
- !Ref Env
- Fn::If:
- IncludeRegion
- !Ref AWS::Region
- !Ref AWS::NoValue
A module that returns an object, invoke-module-b.yaml:
Parameters:
X:
Type: String
Y:
Type: String
Z:
Type: String
Outputs:
Props:
Value:
X: !Ref X
Y: !Ref Y
Z: !Ref Z
The parent template:
Modules:
Label:
Source: invoke-module.yaml
Properties:
Env: prod
App: myapp
Name: "?"
HIJProps:
Source: invoke-module-b.yaml
Properties:
X: x
Y: y
Z: z
Resources:
A:
Type: D::E::F
Properties:
Name:
Fn::Invoke:
- Label
- Name: test
- Id
Name2: !Invoke [Label, {Name: test2}, Id]
WithRegion: !Invoke [Label, {Name: test3, IncludeRegion: true}, Id]
B:
Type: H::I::J
Properties:
Fn::Invoke:
- HIJProps
- Y: yy
- Props
C:
Type: H::I::J
Properties: !Invoke [HIJProps, {Z: zz}, Props]
The packaged template:
Resources:
A:
Type: D::E::F
Properties:
Name: test-myapp-prod
Name2: test2-myapp-prod
WithRegion:
Fn::Join:
- '-'
- - test3
- myapp
- prod
- Ref: AWS::Region
B:
Type: H::I::J
Properties:
X: x
Y: yy
Z: z
C:
Type: H::I::J
Properties:
X: x
Y: y
Z: zz
LabelWhy:
Type: X::Y::Z
Properties:
Id: ?-myapp-prod
The Label module also has a resource, Why. cfnrain adds it to the template as LabelWhy, with the properties from the Modules section. Fn::Invoke does not add resources.
Fn::Join and Fn::Select¶
cfnrain also simplifies two CloudFormation functions when it can resolve them while it packages the template:
Fn::Joinbecomes a plain string when every item in the list is a string. This works in the parent template and in modules.Fn::Selectbecomes the selected item when the list and the index are known.
Fn::Select takes its arguments in the reverse order
cfnrain simplifies Fn::Select only when the list comes first and the index second: Fn::Select: [!Ref Things, 0]. CloudFormation uses the opposite order: Fn::Select: [0, !Ref Things]. If you use the CloudFormation order, cfnrain leaves the function as it is and CloudFormation resolves it. That works. If you use the cfnrain order and cfnrain cannot resolve the list, CloudFormation gets the arguments in the wrong order and the deploy fails. Use the CloudFormation order. See Known issues.
The test for Fn::Select uses the cfnrain order:
Parameters:
Things:
Type: List<String>
Resources:
Foo:
Type: A::B::C
Properties:
Names: !Ref Things
OneName:
Fn::Select:
- !Ref Things
- 0
The packaged template: