

# 在 CloudFormation 模板中创建等待条件
<a name="using-cfn-waitcondition"></a>

本主题介绍了如何在模板中创建等待条件以协调堆栈资源的创建或跟踪配置过程的进度。例如，您可以在应用程序配置部分完成后开始另一个资源的创建，或者也可以在安装和配置过程中发送信号以跟踪其进度。

当 CloudFormation 创建含有等待条件的堆栈时：
+ 它会跟其他任何资源一样创建等待条件，并将等待条件的状态设置为 `CREATE_IN_PROGRESS`。
+ CloudFormation 等待至收到必要数量的成功信号或等待条件的超时时段到期。
+ 如果在超时时段到期之前收到了必要数量的成功信号：
  + 等待条件的状态更改为 `CREATE_COMPLETE`
  + 堆栈创建继续
+ 如果超时到期或收到了故障信号：
  + 等待条件的状态更改为 `CREATE_FAILED`
  + 堆栈回滚

**重要**  
对于 Amazon EC2 和 Auto Scaling 资源，我们建议您使用 CreationPolicy 属性而非等待条件。当实例创建过程成功完成后，将“CreationPolicy”属性添加到这些资源，并使用 cfn-signal 帮助程序脚本发送信号。  
有关更多信息，请参阅 [CreationPolicy 属性](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-creationpolicy.html)。

**注意**  
如果使用 AWS PrivateLink，则响应等待条件的 VPC 中的资源必须能够访问 CloudFormation 特定的 Amazon Simple Storage Service (Amazon S3) 存储桶。资源必须将等待条件响应发送到预签名 Amazon S3 URL。如果这些资源不能向 Amazon S3 发送响应，则 CloudFormation 将不会收到响应，并且堆栈操作会失败。有关更多信息，请参阅[使用接口端点 (AWS PrivateLink) 访问 CloudFormation](vpc-interface-endpoints.md)以及[使用存储桶策略控制从 VPC 端点的访问](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies-vpc-endpoint.html)。

**Topics**
+ [在模板中创建等待条件](#creating-wait-condition)
+ [等待条件信号语法](#wait-condition-signal-syntax)
+ [访问信号数据](#wait-condition-access-signal-data)

## 在模板中创建等待条件
<a name="creating-wait-condition"></a>

**1. 等待条件句柄**  
首先在堆栈模板中定义 [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-waitconditionhandle.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-waitconditionhandle.html) 资源。该资源会生成发送信号所需的预签名 URL。这样您就可以发送信号，而无需提供 AWS 凭证。例如：

```
Resources:
  MyWaitHandle:
    Type: AWS::CloudFormation::WaitConditionHandle
```

**2. 等待条件**  
接下来，在堆栈模板中定义 [https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-waitcondition.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-cloudformation-waitcondition.html) 资源。`AWS::CloudFormation::WaitCondition` 的基本结构如下所示：

```
  MyWaitCondition:
    Type: AWS::CloudFormation::WaitCondition
    Properties:
      Handle: String
      Timeout: String
      Count: Integer
```

`AWS::CloudFormation::WaitCondition` 资源有两个必要属性和一个可选属性。
+ `Handle`（必要）：对模板中声明的 `WaitConditionHandle` 的引用。
+ `Timeout`（必要）：CloudFormation 在收到必要数量的信号之前等待的秒数。`Timeout` 是一种最低时限属性，表示超时不会早于您指定的时间发生，但可能在指定时间后不久发生。您可指定的最长时间为 43200 秒 (12 小时)。
+ `Count`（可选）：CloudFormation 在将等待条件状态设置为 `CREATE_COMPLETE` 并继续创建堆栈前之前必须收到的成功信号数量。如果未指定，则默认值为 1。

通常，您想要等待条件在特定资源创建后立即开始。可以通过为等待条件添加 `DependsOn` 属性来完成此操作。向等待条件添加 `DependsOn` 属性时，CloudFormation 先在 `DependsOn` 属性中创建资源，然后创建等待条件。有关更多信息，请参阅 [DependsOn 属性](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-attribute-dependson.html)。

以下示例展示等待条件：
+ 在成功创建 `MyEC2Instance` 资源后开始
+ 将 `MyWaitHandle` 资源用作 `WaitConditionHandle`
+ 超时为 4500 秒
+ 默认 `Count` 为 1（因为未指定任何 `Count` 属性）

```
  MyWaitCondition:
    Type: AWS::CloudFormation::WaitCondition
    DependsOn: MyEC2Instance
    Properties:
      Handle: !Ref MyWaitHandle
      Timeout: '4500'
```

**3. 发送信号**  
为向 CloudFormation 发出成功或失败的信号，通常需要运行一些代码或脚本。例如，在 EC2 实例上运行的应用程序可能会执行一些额外的配置工作，然后向 CloudFormation 发出信号指示已完成。

信号必须发送至由等待条件句柄生成的预签名 URL。使用预签名 URL 发送成功或失败信号。

**发送信号**

1. 要检索模板中的预签名 URL，需使用带有等待条件句柄逻辑名称的 `Ref` 内置函数。

   如下例所示，您的模板可声明一个 Amazon EC2 实例，并使用 Amazon EC2 `UserData` 属性将预签名 URL 传递到该 EC2 实例。这样在这些实例上运行的脚本或应用程序就可以向 CloudFormation 发出成功或失败的信号。

   ```
     MyEC2Instance:
       Type: AWS::EC2::Instance
       Properties:
       InstanceType: t2.micro  # Example instance type
       ImageId: ami-055e3d4f0bbeb5878  # Change this as needed (Amazon Linux 2023 in us-west-2)
       UserData:
         Fn::Base64: 
           Fn::Join: 
             - ""
             - - "SignalURL="
               - { "Ref": "MyWaitHandle" }
   ```

   这会产生类似于下述信息的 `UserData` 输出：

   ```
   SignalURL=https://amzn-s3-demo-bucket.s3.amazonaws.com/....
   ```

   注意：在 AWS 管理控制台和命令行工具中，预签名 URL 显示为等待条件句柄资源的物理 ID。

1. （可选）要检测堆栈进入等待条件的时间，可以使用以下方法之一：
   + 如果您通过启用的通知创建堆栈，那么 CloudFormation 将向指定主题发布针对每项堆栈事件的通知。如果您或您的应用程序订阅了该主题，您可以监测针对等待条件句柄创建事件的通知，并通过通知消息来检索预签名 URL。
   + 您还可以使用 AWS 管理控制台、AWS CLI 或 SDK 来监控堆栈事件。

1. 您需要通过预签名 URL 发送 HTTP 请求消息之后，才能发送信号。请求方法必须为 `PUT`，并且 `Content-Type` 标题必须为空字符串或省略。请求消息必须为 [等待条件信号语法](#wait-condition-signal-syntax) 指定表单的 JSON 结构。

   您必须发送由 `Count` 属性指定的成功信号数，以便 CloudFormation 继续创建堆栈。如果您的 `Count` 超过 1，则在发送到特定等待条件的所有信号中，每个信号的 `UniqueId` 值必须是唯一的。`UniqueId` 是随机的字母数字字符串。

   `curl` 命令是发送信号的一种方式。以下示例显示了向等待条件发送成功信号的 `curl` 命令行。

   ```
   $ curl -T /tmp/a \
     "https://amzn-s3-demo-bucket.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-west-2%3A034017226601%3Astack%2Fstack-gosar-20110427004224-test-stack-with-WaitCondition--VEYW%2Fe498ce60-70a1-11e0-81a7-5081d0136786%2FmyWaitConditionHandle?Expires=1303976584&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=ik1twT6hpS4cgNAw7wyOoRejVoo%3D"
   ```

   其中文件 *`/tmp/a`* 包含以下 JSON 结构：

   ```
   {
      "Status" : "SUCCESS",
      "Reason" : "Configuration Complete",
      "UniqueId" : "ID1234",
      "Data" : "Application has completed configuration."
   }
   ```

   此示例显示发送同一成功信号的 `curl` 命令行，不同的是，它将 JSON 结构作为命令行参数发送。

   ```
   $ curl -X PUT \
     -H 'Content-Type:' --data-binary '{"Status" : "SUCCESS","Reason" : "Configuration Complete","UniqueId" : "ID1234","Data" : "Application has completed configuration."}' \
     "https://amzn-s3-demo-bucket.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-west-2%3A034017226601%3Astack%2Fstack-gosar-20110427004224-test-stack-with-WaitCondition--VEYW%2Fe498ce60-70a1-11e0-81a7-5081d0136786%2FmyWaitConditionHandle?Expires=1303976584&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=ik1twT6hpS4cgNAw7wyOoRejVoo%3D"
   ```

## 等待条件信号语法
<a name="wait-condition-signal-syntax"></a>

在向等待条件句柄生成的 URL 发送信号时，您必须使用以下 JSON 格式：

```
{
  "Status" : "StatusValue",
  "UniqueId" : "Some UniqueId",
  "Data" : "Some Data",
  "Reason" : "Some Reason"
}
```

### 属性
<a name="wait-condition-signal-properties"></a>

`Status` 字段必须是以下任一值：
+ `SUCCESS`
+ `FAILURE`

`UniqueId` 字段标识发送至 CloudFormation 的信号。如果等待条件的 `Count` 属性大于 1，那么在针对特定等待条件发送的所有信号中，`UniqueId` 值必须唯一；否则，CloudFormation 会将该信号视为对先前已发送的具有相同 `UniqueId` 的信号的重传，并将其忽略。

`Data` 字段可包含要通过信号发回的任何信息。可以通过使用模板中的 [Fn::GetAtt ](resources-section-structure.md#resource-properties-getatt)函数来访问 `Data` 值。

`Reason` 字段为字符串，除与 JSON 格式相一致外，其内容中无任何其他限制。

## 访问信号数据
<a name="wait-condition-access-signal-data"></a>

要访问由有效信号发送的数据，可以在 CloudFormation 模板中为等待条件创建输出值。例如：

```
Outputs:
  WaitConditionData:
    Description: The data passed back as part of signalling the WaitCondition
    Value: !GetAtt MyWaitCondition.Data
```

然后可以使用 [https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stacks.html](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stacks.html) 命令或 CloudFormation 控制台的**输出**选项卡来查看该数据。

`Fn::GetAtt` 函数将返回 `UniqueId` 和 `Data` 作为 JSON 结构中的名称/值对。例如：

```
{"Signal1":"Application has completed configuration."}
```