

# 创建 CloudFormation 宏定义
<a name="template-macros-author"></a>

创建宏定义时，该宏定义会使底层 Lambda 函数在指定的账户中可用，以便 CloudFormation 可以调用该函数来处理模板。

## 事件映射
<a name="template-macros-event-mapping"></a>

当 CloudFormation 调用宏的 Lambda 函数时，它会以 JSON 格式发送请求，其结构如下所示：

```
{
    "region" : "{{us-east-1}}",
    "accountId" : "{{$ACCOUNT_ID}}",
    "fragment" : { {{...}} },
    "transformId" : "{{$TRANSFORM_ID}}",
    "params" : { {{...}} },
    "requestId" : "{{$REQUEST_ID}}",
    "templateParameterValues" : { {{...}} }
}
```
+ `region`

  宏所在的区域。
+ `accountId`

  宏从中调用 Lambda 函数的账户的账户 ID。
+ `fragment`

  可用于自定义处理的模板内容，采用 JSON 格式。
  + 对于 `Transform` 模板部分中包含的宏，这是整个模板，除 `Transform` 部分外。
  + 对于在 `Fn::Transform` 内部函数调用中包含的宏，这包括基于内部函数在模板中的位置的所有同级节点（及其子节点），除 `Fn::Transform` 函数外。有关更多信息，请参阅 [宏模板范围](#template-macros-scope)。
+ `transformId`

  调用此函数的宏的名称。
+ `params`

  对于 `Fn::Transform` 函数调用，是函数的任何指定参数。CloudFormation 在将这些参数传递给函数之前不会进行评估。

  对于在 `Transform` 模板部分中包含的宏，此部分为空。
+ `requestId`

  调用此函数的请求的 ID。
+ `templateParameterValues`

  在模板的 [Parameters](parameters-section-structure.md) 部分中指定的任何参数。CloudFormation 在将这些参数传递给函数之前会进行评估。

## 响应格式
<a name="template-macros-response-format"></a>

CloudFormation 要求 Lambda 函数以如下 JSON 格式返回响应：

```
{
    "requestId" : "{{$REQUEST_ID}}",
    "status" : "{{$STATUS}}",
    "fragment" : { {{...}} },
    "errorMessage": "optional error message for failures"
}
```
+ `requestId`

  调用此函数的请求的 ID。这必须在调用函数时与 CloudFormation 提供的请求 ID 匹配。
+ `status`

  请求的状态（不区分大小写）。应设置为 `success`。CloudFormation 会将任何其他响应都视为失败。
+ `fragment`

  CloudFormation 要包含在已处理模板中的已处理模板内容，包括同级内容。CloudFormation 会将传递给 Lambda 函数的模板内容替换为在 Lambda 响应中收到的模板片段。

  已处理模板内容必须是有效的 JSON，并且其在已处理模板中的包含必须生成有效的模板。

  如果函数实际上没有更改 CloudFormation 传递的模板内容，但您仍需要将该内容包含在已处理模板中，则函数需要将该模板内容在其响应中返回到 CloudFormation。
+ `errorMessage`

  解释转换失败原因的错误消息。CloudFormation 将在堆栈的 **Stack details**（堆栈详细信息）页面的 **Events**（事件）窗格中显示此错误消息。

  例如：

  ```
  Error creating change set: Transform
                              {{AWS 账户 account
                              number}}::{{macro name}} failed with:
                              {{error message string}}.
  ```

## 创建宏定义
<a name="create-a-macro-definition"></a>

**创建 CloudFormation 宏定义**

1. [构建 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html)来处理模板内容。该函数可以处理模板的任何部分，甚至是整个模板。

1. 创建包含 `AWS::CloudFormation::Macro` 资源类型的 CloudFormation 模板，并指定 `Name` 和 `FunctionName` 属性。`FunctionName` 属性必须包含在 CloudFormation 运行宏时调用的 Lambda 函数的 ARN。

1. （可选）为了帮助调试，您还可以在为宏创建 `AWS::CloudFormation::Macro` 资源类型时指定 `LogGroupName` 和 `LogRoleArn` 属性。借助这些属性，您可以指定 CloudFormation 在调用宏的底层 Lambda 函数时向其发送错误日志信息的 CloudWatch Logs 日志组，以及 CloudFormation 在将日志条目发送到这些日志时应代入的角色。

1. 在要使用宏的账户中使用带宏的模板[创建堆栈](cfn-console-create-stack.md)。或在管理员账户中使用带宏的模板[创建具有自行管理权限的堆栈集](stacksets-getting-started-create-self-managed.md)，然后在目标账户中创建堆栈实例。

1. 在 CloudFormation 成功创建包含宏定义的堆栈之后，该宏便可在这些账户中使用。您可以通过在模板中，在与要处理的模板内容相关的适当位置引用宏来使用宏。

## 宏模板范围
<a name="template-macros-scope"></a>

在模板的 `Transform` 部分中引用的宏可以处理该模板的全部内容。

在 `Fn::Transform` 函数中引用的宏可以处理模板中该 `Fn::Transform` 函数的任何同级元素（包括子元素）的内容。

例如，在下面的模板示例中，`AWS::Include` 可以根据包含它的 `Fn::Transform` 函数的位置处理 `MyBucket` 属性。`MyMacro` 可以处理整个模板的内容，因为它包含在 `Transform` 部分中。

```
# Start of processable content for MyMacro
AWSTemplateFormatVersion: 2010-09-09 
 Transform: [MyMacro]
 Resources:
    WaitCondition:
      Type: AWS::CloudFormation::WaitCondition
    MyBucket:
      Type: AWS::S3::Bucket
      # Start of processable content for AWS::Include
      Properties:
        BucketName: {{amzn-s3-demo-bucket1}}
        Tags: {{[{"key":"value"}]}} 
        'Fn::Transform':
          - Name: 'AWS::Include'
              Parameters:
                Location: {{s3://amzn-s3-demo-bucket2/MyFileName.yaml}}
        CorsConfiguration: {{[]}}
        # End of processable content for AWS::Include
    MyEc2Instance:
      Type: AWS::EC2::Instance
      Properties:
        ImageID: {{ami-1234567890abcdef0}}
# End of processable content for MyMacro
```

## 宏评估顺序
<a name="template-macros-order"></a>

您可以在给定模板中引用多个宏，包括由 CloudFormation 托管的转换，例如 [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/transform-aws-include.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/transform-aws-include.html) 和 [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/transform-aws-serverless.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/transform-aws-serverless.html)。

将会根据宏在模板中的位置，从嵌套最深的宏向外直到最一般的宏，按顺序评估宏。对于模板中相同位置的宏，将会根据列出的顺序按顺序进行评估。

诸如 `AWS::Include` 和 `AWS::Transform` 之类的转换在操作顺序和范围方面被视为与任何其他宏相同。

例如，在下面的模板示例中，CloudFormation 会首先评估 `PolicyAdder` 宏，因为这是模板中最深的嵌套宏。然后，CloudFormation 会首先评估 `MyMacro`，然后再评估 `AWS::Serverless`，因为在 `Transform` 部分中它列于 `AWS::Serverless` 之前。

```
AWSTemplateFormatVersion: 2010-09-09
 Transform: [MyMacro, AWS::Serverless]
 Resources:
    WaitCondition:
      Type: AWS::CloudFormation::WaitCondition
    MyBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: {{amzn-s3-demo-bucket}}
        Tags: {{[{"key":"value"}]}}
        'Fn::Transform':
          - Name: PolicyAdder
        CorsConfiguration: {{[]}}
    MyEc2Instance:
      Type: AWS::EC2::Instance
      Properties:
        ImageID: {{ami-1234567890abcdef0}}
```