I am working on AWS CloudFormation and I created one template in which I asked user to select Environment.
On the basis of selected value I created the resources.
The accepted answer suggested using a CloudFormation macro, and another answer suggesting using FindInMap
.
FindInMap
is not very useful here, since it would only work with hardcoded values.
The macro suggestion will work, but requires quite a bit of setup (declare the macro in a separate stack, ensure your deployer role has permission to invoke the Lambda, and your CloudFormation stack is deployed with CAPABILITY_AUTO_EXPAND
, and so on).
Declaring a custom resource within the template will work and IMO involves less work than relying on the macro. Here's a CFN snippet, adapting the S3 bucket resource you were asking about, demonstrating the use of a custom resource which will lowercase an arbitrary S3 bucket name:
# Custom resource to transform input to lowercase.
LowerCaseLambda:
Type: 'AWS::Lambda::Function'
Properties:
Description: Returns the lowercase version of a string
MemorySize: 256
Runtime: python3.8
Handler: index.lambda_handler
Role: !GetAtt LowerCaseLambdaRole.Arn
Timeout: 30
Code:
ZipFile: |
import cfnresponse
def lambda_handler(event, context):
output = event['ResourceProperties'].get('InputString', '').lower()
responseData = {'OutputString': output}
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
LowerCaseLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
Policies:
- PolicyName: "lambda-write-logs"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
Resource: "arn:aws:logs:*:*"
S3BucketName:
Type: Custom::Lowercase
Properties:
ServiceToken: !GetAtt LowerCaseLambda.Arn
InputString: !Ref selectedEnv
S3Bucket:
BucketName: !Join
- ''
- - !GetAtt S3BucketName.OutputString
- "-deployment.companyname.com"
You can do this with a CloudFormation macro.
Parameters:
InputString:
Default: "This is a test input string"
Type: String
Resources:
S3Bucket:
Type: "AWS::S3::Bucket"
Properties:
Tags:
- Key: Upper
Value:
'Fn::Transform':
- Name: 'String'
Parameters:
InputString: !Ref InputString
Operation: Upper
https://github.com/awslabs/aws-cloudformation-templates/tree/master/aws/services/CloudFormation/MacrosExamples/StringFunctions
Mr. Young is correct, that is the syntax you need to use to invoke the macros.
HOWEVER, the key factor which both they and the documentation failed to mention is that in order to invoke the transform macros that you need to deploy this stack into your accounts BEFORE you can use the functions listed in the ReadMe.
https://github.com/awslabs/aws-cloudformation-templates/blob/master/aws/services/CloudFormation/MacrosExamples/StringFunctions/string.yaml
I think the docs could be clarified in this regard, I'll see if I can PR a clarification
I got the answer of this question. For this I have used Mappings JSON in which I have added values like If Selected value is DEV then use dev, If QA then qa like this, and used below JSON which used Fn:FindInMap
[ { "Fn::FindInMap": [ "Enviroment", "PlatformName", { "Ref": "selectedEnv" } ] }, "clientname" ]
Below is the Mappings JSON:
"Mappings" : { "Enviroment" : { "PlatformName" : { "DEV" : "dev", "QA" : "qa", "UAT" : "uat", "PROD" : "prod" } } }