

# Amazon SNS 支持的自定义资源
<a name="template-custom-resources-sns"></a>

以下主题展示了如何使用服务令牌配置自定义资源，该令牌指定了 CloudFormation 向其发送请求的 Amazon SNS 主题。您还将了解自定义资源堆栈创建、更新和删除过程中发送和接收的事件和消息的顺序。

通过自定义资源和 Amazon SNS，您可以启用方案，例如向堆栈添加新资源和向堆栈注入动态数据。例如，创建堆栈时，CloudFormation 可以向被 Amazon EC2 实例上运行的应用程序监控的主题发送 `Create` 请求。Amazon SNS 通知触发应用程序以执行其他预置任务，如检索列在白名单中的弹性 IP 池。完成后，应用程序发送响应（和任何输出数据），通知 CloudFormation 继续执行堆栈操作。

将 Amazon SNS 主题指定为自定义资源的目标时，CloudFormation 会在涉及自定义资源的堆栈操作期间，向指定的 SNS 主题发送消息。要处理这些消息并执行必要的操作，必须有一个订阅 SNS 主题的受支持端点。

有关自定义资源及其工作原理的介绍，请参阅[自定义资源的工作原理](template-custom-resources.md#how-custom-resources-work)。有关 Amazon SNS 及其工作原理的信息，请参阅 [Amazon Simple Notification Service Developer Guide](https://docs.aws.amazon.com/sns/latest/dg/)。

## 使用 Amazon SNS 创建自定义资源
<a name="walkthrough-custom-resources-sns-adding-nonaws-resource"></a>

**Topics**
+ [步骤 1：堆栈创建](#crpg-walkthrough-stack-creation)
+ [步骤 2：堆栈更新](#crpg-walkthrough-stack-updates)
+ [步骤 3：堆栈删除](#crpg-walkthrough-stack-deletion)

### 步骤 1：堆栈创建
<a name="crpg-walkthrough-stack-creation"></a>

1. <a name="crpg-walkthrough-stack-creation-customer-template"></a>模板开发人员创建包含自定义资源的 CloudFormation 堆栈。

   在以下模板示例中，对具有逻辑 ID `Custom::SeleniumTester` 的自定义资源使用自定义资源类型名称 `MySeleniumTest`。自定义资源类型名称必须是字母数字字符，最大长度为 60 个字符。

   自定义资源类型是使用服务令牌、可选提供商特定属性以及由自定义资源提供商定义的可选 [Fn::GetAtt](resources-section-structure.md#resource-properties-getatt) 属性声明的。使用这些属性和特性可以将信息从template developer传递给custom resource provider，反之亦然。服务令牌指定资源提供商已配置的 Amazon SNS 主题。

   ```
   {
      "AWSTemplateFormatVersion" : "2010-09-09",
      "Resources" : {
         "MySeleniumTest" : {
            "Type": "Custom::SeleniumTester",
            "Version" : "1.0",
            "Properties" : {
               "ServiceToken": "arn:aws:sns:us-west-2:123456789012:CRTest",
               "seleniumTester" : "SeleniumTest()",
               "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
               "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
            }
         }
      },
      "Outputs" : {
         "topItem" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
         },
         "numRespondents" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
         }
      }
   }
   ```
**注意**  
在提供商响应 CloudFormation 期间，自定义资源提供商会返回使用 `Fn::GetAtt` 访问的数据的名称和值。如果custom resource provider是第三方，则template developer必须从custom resource provider获取这些返回值的名称。

1. <a name="crpg-walkthrough-stack-creation-provider-request"></a>CloudFormation 使用 `"RequestType" : "Create"` 向资源提供者发送一条 Amazon SNS 通知，其中包含有关堆栈的信息、堆栈模板中的自定义资源属性和用于响应的 S3 URL。

   用于发送通知的 SNS 主题嵌入在模板的 `ServiceToken` 属性中。要避免使用硬编码值，模板开发人员可以使用模板参数，以便在启动堆栈时输入值。

   以下示例显示一个自定义资源 `Create` 请求，其中包含一个用 `Custom::SeleniumTester` 的 `LogicalResourceId` 创建的自定义资源类型名称 `MySeleniumTester`：

   ```
   {
      "RequestType" : "Create",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
      }
   }
   ```

   有关 `Create` 请求的请求对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

1. <a name="crpg-walkthrough-stack-creation-provider-response"></a>custom resource provider处理template developer发送的数据，并确定 `Create` 请求是否已成功。然后，资源提供者使用 CloudFormation 发送的 S3 URL 来发送 `SUCCESS` 或 `FAILED` 响应。

   根据响应类型，CloudFormation 将需要不同的响应字段。有关特定请求类型的响应字段的信息，请参阅 [请求和响应参考](crpg-ref.md) 部分中该请求类型的文档。

   在响应创建或更新请求时，custom resource provider 可以在响应的 `Data` 字段中返回数据元素。这些是名称/值对，*名称*对应于用于堆栈模板中的自定义资源的 `Fn::GetAtt` 属性。该*值*是模板开发人员对具有此属性名称的资源调用 `Fn::GetAtt` 时返回的数据。

   以下是自定义资源响应的示例：

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "Data" : {
         "resultsPage" : "http://www.myexampledomain/test-results/guid",
         "lastUpdate" : "2012-11-14T03:30Z"
      }
   }
   ```

   有关 `Create` 请求的响应对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

   `StackId`、`RequestId` 和 `LogicalResourceId` 字段必须从请求中逐字复制。

1. <a name="crpg-walkthrough-stack-creation-stack-status"></a> CloudFormation 将堆栈状态声明为 `CREATE_COMPLETE` 或 `CREATE_FAILED`。如果堆栈已成功创建，模板开发人员通过 [Fn::GetAtt](resources-section-structure.md#resource-properties-getatt) 访问已创建的自定义资源的输出值，可以使用这些值。

   例如，用于举例说明的自定义资源模板使用 `Fn::GetAtt` 将资源输出复制到堆栈输出：

   ```
   "Outputs" : {
      "topItem" : {
         "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
      },
      "numRespondents" : {
         "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
      }
   }
   ```

### 步骤 2：堆栈更新
<a name="crpg-walkthrough-stack-updates"></a>

要更新现有堆栈，您必须提交一个指定了堆栈资源属性更新的模板，如下面的示例所示。CloudFormation 只更新模板中指定了更改的资源。有关更多信息，请参阅 [理解堆栈资源的更新行为](using-cfn-updating-stacks-update-behaviors.md)。

您可以更新需要替换基础物理资源的自定义资源。在 CloudFormation 模板中更新某个自定义资源时，CloudFormation 会向该自定义资源发送更新请求。如果需要替换自定义资源，新的自定义资源必须使用新的物理 ID 发送响应。CloudFormation 收到响应时，会比较新旧自定义资源的 `PhysicalResourceId`。如果不同，CloudFormation 会将更新视为替换，并向旧资源发送删除请求，如 [步骤 3：堆栈删除](#crpg-walkthrough-stack-deletion) 中所示。

**注意**  
如果您没有对自定义资源进行更改，CloudFormation 在堆栈更新过程中不会向资源发送请求。

1. <a name="crpg-walkthrough-stack-updates-customer-template"></a>template developer启动对包含自定义资源的堆栈的更新。在更新期间，template developer可以在堆栈模板中指定新属性。

   下面是一个使用自定义资源类型的堆栈模板 `Update` 示例：

   ```
   {
      "AWSTemplateFormatVersion" : "2010-09-09",
      "Resources" : {
         "MySeleniumTest" : {
            "Type": "Custom::SeleniumTester",
            "Version" : "1.0",
            "Properties" : {
               "ServiceToken": "arn:aws:sns:us-west-2:123456789012:CRTest",
               "seleniumTester" : "SeleniumTest()",
               "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
                  "http://mynewsite.com" ],
               "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
            }
         }
      },
      "Outputs" : {
         "topItem" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "resultsPage"] }
         },
         "numRespondents" : {
            "Value" : { "Fn::GetAtt" : ["MySeleniumTest", "lastUpdate"] }
         }
      }
   }
   ```

1. <a name="crpg-walkthrough-stack-updates-provider-request"></a>CloudFormation 会使用 `"RequestType" : "Update"` 向资源提供者发送一条 Amazon SNS 通知，其中包含与 `Create` 调用类似的信息，不同的是，`OldResourceProperties` 字段包含旧的资源属性，而 ResourceProperties 包含已更新的（如果有）资源属性。

   以下是一个 `Update` 请求的示例：

   ```
   {
      "RequestType" : "Update",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
            "http://mynewsite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
      },
      "OldResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4" ]
      }
   }
   ```

   有关 `Update` 请求的请求对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

1. <a name="crpg-walkthrough-stack-updates-provider-response"></a>自定义资源提供商处理由 CloudFormation 发送的数据。自定义资源执行更新并向 S3 URL 发送 `SUCCESS` 或 `FAILED` 响应。然后，CloudFormation 比较新旧自定义资源的 `PhysicalResourceIDs`。如果不同，CloudFormation 将认为更新需要替换，并向旧资源发送删除请求。下面的示例说明custom resource provider对 `Update` 请求的响应。

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester2"
   }
   ```

   有关 `Update` 请求的响应对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

   `StackId`、`RequestId` 和 `LogicalResourceId` 字段必须从请求中逐字复制。

1. <a name="crpg-walkthrough-stack-updates-stack-status"></a>CloudFormation 将堆栈状态声明为 `UPDATE_COMPLETE` 或 `UPDATE_FAILED`。如果更新失败，堆栈将回滚。如果堆栈更新成功，template developer可以使用 `Fn::GetAtt` 访问已创建自定义资源的任何新输出值。

### 步骤 3：堆栈删除
<a name="crpg-walkthrough-stack-deletion"></a>

1. <a name="crpg-walkthrough-stack-deletion-customer-template"></a>模板开发人员删除包含自定义资源的堆栈。CloudFormation 将获取堆栈模板中指定的当前属性及 SNS 主题，并准备向自定义资源提供商发出请求。

1. <a name="crpg-walkthrough-stack-deletion-provider-request"></a>CloudFormation 使用 `"RequestType" : "Delete"` 向资源提供者发送一条 Amazon SNS 通知，其中包含有关堆栈的当前信息、堆栈模板中的自定义资源属性和用于响应的 S3 URL。

   只要您删除堆栈或进行自定义资源的删除或替换更新，CloudFormation 都会比较新旧自定义资源的 `PhysicalResourceId`。如果不同，CloudFormation 会将更新视为替换，并向旧资源 (`OldPhysicalResource`) 发送删除请求，如下面的 `Delete` 请求示例所示。

   ```
   {
      "RequestType" : "Delete",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "ResponseURL" : "http://pre-signed-S3-url-for-response",
      "ResourceType" : "Custom::SeleniumTester",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1",
      "ResourceProperties" : {
         "seleniumTester" : "SeleniumTest()",
         "endpoints" : [ "http://mysite.com", "http://myecommercesite.com/", "http://search.mysite.com",
            "http://mynewsite.com" ],
         "frequencyOfTestsPerHour" : [ "3", "2", "4", "3" ]
      }
   }
   ```

   有关 `Delete` 请求的请求对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

   `DescribeStackResource`、`DescribeStackResources` 和 `ListStackResources` 显示用户定义的名称 (如果已指定)。

1. <a name="crpg-walkthrough-stack-deletion-provider-response"></a>自定义资源提供商处理 CloudFormation 发送的数据，并确定 `Delete` 请求是否已成功。然后，资源提供者使用 CloudFormation 发送的 S3 URL 来发送 `SUCCESS` 或 `FAILED` 响应。要成功删除带自定义资源的堆栈，custom resource provider 必须成功响应删除请求。

   以下是custom resource provider响应 `Delete` 请求的示例：

   ```
   {
      "Status" : "SUCCESS",
      "RequestId" : "unique-request-id",
      "StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/mystack/5b918d10-cd98-11ea-90d5-0a9cd3354c10",
      "LogicalResourceId" : "MySeleniumTester",
      "PhysicalResourceId" : "Tester1"
   }
   ```

   有关 `Delete` 请求的响应对象的详细信息，请参阅 [请求和响应参考](crpg-ref.md) 主题。

   `StackId`、`RequestId` 和 `LogicalResourceId` 字段必须从请求中逐字复制。

1. <a name="crpg-walkthrough-stack-updates-stack-status-delete"></a>CloudFormation 将堆栈状态声明为 `DELETE_COMPLETE` 或 `DELETE_FAILED`。