资料
- 使用 AWS CloudFormation 宏对模板执行自定义处理
- Macros Examples
- 使用 AWS Lambda 支持的宏扩展 AWS CloudFormation
宏的理解
在cfn模板的创建过程中,我们会使用内置函数和伪函数对配置参数进行进一步处理,避免冗长的写法,更灵活的配置堆栈。但是仅仅使用托管的cfn内置函数可能仍旧无法满足我们的需要,这个时候我们就可以使用宏函数进行定制。
顾名思义,宏就是一段处理函数,处理的内容是cfn模板本身
我们可以创建类型为AWS::CloudFormation::Macro,该资源能够在cfn中调用lambda函数
cfn模板宏的执行逻辑如下
从上图可以看出,宏的使用方式有两种:
-
Fn::Transform,处理模板的一部分
-
在模板的
Transform
部分指定,处理整个模板Transform: - MyMacro - 'AWS::Serverless'
cfn有一些宏是托管的,最常用的有:
-
AWS::Serverless ,通过sam的写法简化lambda函数的创建
-
AWS::Include ,引入cfn模板片段,无法嵌套include
# 最终渲染的结果是有两个WaitHandle资源 $ cat single_wait_condition.yaml WebServerWaitHandle: Type: 'AWS::CloudFormation::WaitConditionHandle' $ cat main.yaml Resources: MyWaitHandle: Type: 'AWS::CloudFormation::WaitConditionHandle' 'Fn::Transform': Name: 'AWS::Include' Parameters: Location : "s3://MyAmazonS3BucketName/single_wait_condition.yaml"
此外还有以下注意点:
- 宏依赖lambda函数
- 宏的解析在模板处理之前,宏在内部函数之前处理
- 宏中无法嵌套宏
- 引用宏的堆栈无法通过更改集更新,只能直接更新或重建
测试宏
创建cfn堆栈测试,我们直接以示例String function
中的宏啦测试
注意:需要开启以下权限CAPABILITY_AUTO_EXPAND
CAPABILITY_AUTO_EXPAND
Some templates reference macros. If your stack set template references one or more macros, you must create the stack set directly from the processed template, without first reviewing the resulting changes in a change set. To create the stack set directly, you must acknowledge this capability
string function宏的用法如下,不同场景示例参考(upper,lower,replace等),使用经典的一句话26字母
Parameters:
InputString:
Default: "The quick brown fox jumps over a lazy dog"
Type: String
Resources:
S3Bucket:
Type: "AWS::S3::Bucket"
Properties:
Tags:
- Key: Upper
Value:
'Fn::Transform':
- Name: 'String'
Parameters:
InputString: !Ref InputString
Operation: Upper
查看string function创建的lambda处理函数,实际上就是对params.InputString参数按照Operation进行处理,抓取下事件信息
import traceback
def handler(event, context):
print(event)
response = {
"requestId": event["requestId"],
"status": "success"
}
try:
operation = event["params"]["Operation"]
input = event["params"]["InputString"]
no_param_string_funcs = ["Upper", "Lower", "Capitalize", "Title", "SwapCase"]
if operation in no_param_string_funcs:
response["fragment"] = getattr(input, operation.lower())()
elif operation == "Strip":
chars = None
if "Chars" in event["params"]:
chars = event["params"]["Chars"]
response["fragment"] = input.strip(chars)
elif operation == "Replace":
old = event["params"]["Old"]
new = event["params"]["New"]
response["fragment"] = input.replace(old, new)
elif operation == "MaxLength":
length = int(event["params"]["Length"])
if len(input) <= length:
response["fragment"] = input
elif "StripFrom" in event["params"]:
if event["params"]["StripFrom"] == "Left":
response["fragment"] = input[len(input)-length:]
elif event["params"]["StripFrom"] != "Right":
response["status"] = "failure"
else:
response["fragment"] = input[:length]
else:
response["status"] = "failure"
except Exception as e:
traceback.print_exc()
response["status"] = "failure"
response["errorMessage"] = str(e)
return response
转换之前的模板
Parameters:
InputString:
Default: "The quick brown fox jumps over a lazy dog"
Type: String
Resources:
S3Bucket:
Type: "AWS::S3::Bucket"
Properties:
Tags:
- Key: Upper
Value:
'Fn::Transform':
- Name: 'String'
Parameters:
InputString: !Ref InputString
Operation: Upper
转换之后的模板
Parameters:
InputString:
Default: The quick brown fox jumps over a lazy dog
Type: String
Resources:
S3Bucket:
Properties:
Tags:
- Value: THE QUICK BROWN FOX JUMPS OVER A LAZY DOG
Key: Upper
Type: AWS::S3::Bucket
查看下cw log的日志观察下请求和响应
{
"accountId": "xxxxxxxxxxxx",
"fragment": {},
"transformId": "xxxxxxxxxxxx::String",
"requestId": "da2a76a3-594c-4b8b-9d13-d571bcf631b5",
"region": "cn-north-1",
"params": {
"InputString": "The quick brown fox jumps over a lazy dog",
"Operation": "Upper"
},
"templateParameterValues": {
"InputString": "The quick brown fox jumps over a lazy dog"
}
}
响应,cfn会将fragment中的值提取出来作为模板的内容
The processed template content for AWS CloudFormation to include in the processed template, including siblings. AWS CloudFormation replaces the template content that is passed to the Lambda function with the template fragment it receives in the Lambda response.
{
"requestId": "f42a896f-c9e0-4560-8996-0ef5b72d3ae2",
"status": "success",
"fragment": "THE QUICK BROWN FOX JUMPS OVER A LAZY DOG"
}