

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 为 EBS 快照创建 Amazon Data Lifecycle Manager 自定义策略
<a name="snapshot-ami-policy"></a>

以下程序说明了如何使用 Amazon Data Lifecycle Manager 来自动执行 Amazon EBS 快照生命周期。

**Topics**
+ [创建快照生命周期策略](#create-snap-policy)
+ [快照生命周期策略的注意事项](#snapshot-considerations)
+ [其他资源](#snapshot-additional-resources)
+ [自动生成应用程序一致性快照](automate-app-consistent-backups.md)
+ [前置和后置脚本的其他用例](script-other-use-cases.md)
+ [前置和后置脚本的工作方式](script-flow.md)
+ [识别使用前置和后置脚本创建的快照](dlm-script-tags.md)
+ [监控前置和后置脚本](dlm-script-monitoring.md)

## 创建快照生命周期策略
<a name="create-snap-policy"></a>

使用以下过程之一创建快照生命周期策略。

------
#### [ Console ]

**要创建快照策略**

1. 打开位于 [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/) 的 Amazon EC2 控制台。

1. 在导航窗格中，依次选择 **Elastic Block Store** 和**生命周期管理器**，然后选择**创建生命周期策略**。

1. 在**选择策略类型**页面上，选择 **EBS 快照策略**，然后选择**下一步**。

1. 在**目标资源**部分中，执行以下操作：

   1. 对于**目标资源类型**，选择要备份的资源的类型。选择 `Volume` 创建各个卷的快照，或选择 `Instance` 从挂载到实例的卷创建多卷快照。

   1. （*仅限 Outpost 和本地区域客户*）请指定目标资源的位置。

      对于**目标资源位置**，请指定目标资源的位置。
      + 要定位某个区域中的资源，请选择 **AWS 区域**。Amazon Data Lifecycle Manager 将仅备份在当前区域中具有匹配目标标签的所有指定类型的资源。快照是在同一区域内创建的。
      + 要定位本地区域中的资源，请选择 **AWS Local Zones**。Amazon Data Lifecycle Manager 将仅备份在当前区域中的所有本地区域中具有匹配目标标签的所有指定类型的资源。快照可以在与源资源相同的本地区域中创建，也可以在其父区域中创建。
      + 要定位 Outpost 上的资源，请选择 **AWS Outpost**。Amazon Data Lifecycle Manager 将备份您的账户中所有 Outposts 上具有匹配目标标签的全部指定类型资源。快照可以在与源资源相同的 Outpost 上创建，也可以在其父区域中创建。

   1. 对于**目标资源标签**，选择标识要备份的卷或实例的资源标签。策略只备份具有指定标签键和值对的资源。

1. 对于**描述**，输入策略的简短描述。

1. 对于 **IAM 角色**，选择一个有权管理快照以及描述卷和实例的 IAM 角色。要使用 Amazon Data Lifecycle Manager 提供的默认角色。请选择**默认角色**。或者，要使用您之前创建的自定义 IAM 角色，请选择**选择其他角色**，然后选择要使用的角色。

1. 对于**策略标签**，选择要应用于生命周期策略的标签。您可以使用这些标签对策略进行标识和分类。

1. 对于 **Policy status**（策略状态），选择 **Enable**（启用），以在下次计划时间开启策略运行，或者选择 **Disable policy**（禁用策略）以禁止策略运行。如果您现在不启用该策略，则该策略仅在创建后手动启用之后开始创建快照。

1. （*仅限以实例为目标的策略*）从多卷快照集中排除卷。

   默认情况下，Amazon Data Lifecycle Manager 将创建附加到目标实例的所有卷的快照。不过，您可以选择创建附加卷子集的快照。在 **Parameters **（参数）部分，执行以下操作：
   + 如果您不想创建附加到目标实例的根卷的快照，请选择 **Exclude root volume**（排除根卷）。如果选择此选项，则只有附加到目标实例的数据（非根）卷才会包含在多卷快照集中。
   + 如果要创建附加到目标实例的数据（非根）卷子集的快照，请选择**排除特定的数据卷**，然后指定用于标识不应创建快照的数据卷的标签。Amazon Data Lifecycle Manager 不会为具有任何指定标签的数据卷创建快照。Amazon Data Lifecycle Manager 仅为不具有任何指定标签的数据卷创建快照。

1. 选择**下一步**。

1. 在**配置计划**屏幕上，配置策略计划。一个策略最多可以有 4 个计划。计划 1 是强制要求的计划。计划 2、3、4 是可选计划。对于您添加的每个策略计划，请执行以下操作：

   1. 在**计划详细信息**部分中，执行以下操作：

      1. 对于**计划名称**，请指定计划的描述性名称。

      1. 在**频率**和相关字段中配置策略运行之间的间隔。

         您可以按每日、每周、每月或每年计划配置策略运行。或者，选择**自定义 cron 表达式**以指定不超过一年的间隔时间。有关更多信息，请参阅 *Amazon EventBridge 用户指南*中的 [Cron 和费率表达式](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-scheduled-rule-pattern.html)。
**注意**  
如果您需要为此计划启用 **snapshot archiving**（快照存档），则必须选择 **monthly**（每月）或 **yearly**（每年）频率，或者指定一个创建频率至少为 28 天的 cron 表达式。  
如果指定一个将在特定周次的特定日期（例如，当月第二周星期四）创建快照的每月频率，则对于基于计数的计划，存档层的保留计数必须为 4 或以上。

      1. 对于**开始时间**，请指定计划开始运行策略的时间。第一次策略运行在计划时间之后的一小时内开始。时间必须输入 `hh:mm` UTC 格式。

      1. 对于**保留类型**，请指定计划创建的快照的保留策略。

         您可以根据其总计数或存在时间保留快照。
         + 基于计数的保留
           + 禁用快照归档后，范围为 `1` 到 `1000`。当达到保留阈值时，最早的快照将永久删除。
           + 启用快照归档后，范围为 `0`（创建后立即归档）到 `1000`。达到保留阈值时，最早的快照将转换为完整快照，然后移动到存档层。
         + 基于时长的保留
           + 禁用快照归档后，范围为 `1` 天到 `100` 年。当达到保留阈值时，最早的快照将永久删除。
           + 启用快照归档后，范围为 `0` 天（创建后立即归档）到 `100` 年。达到保留阈值时，最早的快照将转换为完整快照，然后移动到存档层。
**注意**  
所有计划必须具有相同的保留类型（基于期限或基于计数）。您只能为“计划 1”指定保留类型。计划 2、3、4 会继承计划 1 的保留类型。每个计划都可以有自己的保留计数或期限。
如果您启用了快速快照还原、跨区域复制或快照共享，则必须指定 `1` 或更大的保留计数，或者 `1` 天或更长的保留期。

      1. （*AWS Outposts 仅限本地区域客户*）指定快照目标。

         对于**快照目标** – 请指定策略创建的快照目标。
         + 如果该政策针对的是某个区域中的资源，则必须在同一区域创建快照。 AWS 已选定您的区域。
         + 如果策略的目标是本地区域中的资源，则可以在与源资源相同的本地区域中创建快照，也可以在其父区域中创建快照。
         + 如果策略的目标是 Outpost 上的资源，则可以在与源资源相同的 Outpost 上创建快照，也可以在其父区域中创建快照。

   1. 配置快照标签。

      在**标记**部分中，请执行以下操作：

      1. 要将所有用户定义的标签从源卷复制到计划创建的快照，请选择**从源中复制标签**。

      1. 要指定分配给由该计划创建的快照的其他标签，请选择**添加标签**。

   1. 配置应用程序一致性快照的前置和后置脚本。

      有关更多信息，请参阅 [使用 Data Lifecycle Manager 自动生成应用程序一致性快照](automate-app-consistent-backups.md)。

   1. （*仅限以卷为目标的策略*）配置快照存档。

      在**快照存档**部分，请执行以下操作：
**注意**  
您在一个策略中只能为一个计划启用快照存档。

      1. 要为此计划启用快照存档，请选择 **Archive snapshots created by this schedule**（将此计划创建的快照存档）。
**注意**  
只有在快照创建频率为每月或每年，或者指定一个创建频率至少为 28 天的 cron 表达式时，才能启用快照存档。

      1. 为存档层中的快照指定保留规则。
         + 对于**基于计数的计划**，指定要在存档层中保留的快照数量。当达到保留阈值时，最老的快照将从存档层中永久删除。例如，假设您指定 3，则计划将在存档层中最多保留 3 个快照。存档第四个快照时，系统将会删除存档层中三个现有快照中最老的一个。
         + 对于**基于期限的计划**，指定要在存档层中保留快照的期限。当达到保留阈值时，最老的快照将从存档层中永久删除。例如，假设您指定 120 天，则计划将在该期限届满时自动从存档层中删除快照。
**重要**  
存档快照的最短保留期为 90 天。必须指定一个会将快照保留至少 90 天的保留规则。

   1. 启用快速快照还原。

      要为计划创建的快照启用快速快照还原，请在**快速快照还原**部分中选择**启用快速快照还原**。如果您启用快速快照还原，则必须选择要在其中启用该功能的可用区。如果计划使用基于时间的保留计划，则必须指定为每个快照启用快速快照还原的时间段。如果计划使用基于计数的保留，您必须指定要启用快速快照还原的最大快照数。

      如果计划在 Outpost 上创建快照，则无法启用快速快照还原。存储在 Outpost 上的本地快照不支持快速快照还原。
**注意**  
对于为特定可用区中快照启用的快速快照还原，您需要按每分钟支付费用。收费按比例计算，最少 1 小时。

   1. 配置跨区域复制。

      要将计划创建的快照复制到 Outpost 或其他区域，请在**跨区域复制**部分中选择**启用跨区域复制**。

      如果计划在区域中创建快照，则您可以将快照复制到账户中最多三个其他区域或 Outposts。您必须为每个目标区域或 Outpost 指定单独的跨区域复制规则。

      对于每个区域或 Outpost，您可以选择不同的保留策略，还可以选择复制所有标签还是不复制任何标签。如果源快照已加密或默认启用加密，则会加密已复制的快照。如果源快照未加密，您可以启用加密。如果未指定 KMS 密钥，则会在每个目标区域中使用 EBS 加密的默认 KMS 密钥 对快照进行加密。如果您为目标区域指定 KMS 密钥，则选定的 IAM 角色必须具有对 KMS 密钥 的访问权限。
**注意**  
您必须确保没有超过每个区域的并发快照副本数。

       如果策略在 Outpost 上创建快照，则无法将快照复制到区域或另一个 Outpost，并且跨区域复制设置不可用。

   1. 配置跨账户共享。

      在**跨账户共享**中，将策略配置为自动与其他 AWS 账户共享计划创建的快照。执行以下操作：

      1. 要启用与其他 AWS 账户共享，请选择**启用跨账户共享**。

      1. 要添加要与之共享快照的账户，请选择**添加账户**，输入 12 位 AWS 账户 ID，然后选择**添加**。

      1. 要在特定时间段后自动取消共享所共享的快照，请选择 **Unshare automatically**（自动取消共享）。如果您选择自动将共享快照取消共享，则自动取消快照共享前的持续时间不能超过策略保留其快照的期限。例如，如果策略的保留配置可将快照保留 5 天，则您可以将策略配置为在最多 4 天的时间后自动取消快照共享。这适用于采用基于存在时间和基于计数的快照保留配置的策略。

         如果不启用自动取消共享，快照将一直共享直至删除。
**注意**  
您只能共享未加密的快照或使用 客户托管密钥 加密的快照。您无法共享使用默认 EBS 加密 KMS 密钥 加密的快照。如果您共享加密快照，则还必须与目标账户共享用于加密源卷的 KMS 密钥。有关更多信息，请参阅 *AWS Key Management Service 开发人员指南*中的[允许其他账户中的用户使用 KMS 密钥](https://docs.aws.amazon.com//kms/latest/developerguide/key-policy-modifying-external-accounts.html)。

   1. 要添加其他计划，请选择位于页面顶部的**添加其他计划**。每个其他计划请按照本主题之前所述填写字段。

   1. 添加所需计划之后，请选择**查看策略**。

1. 查看策略摘要，然后选择**创建策略**。
**注意**  
如果发生 `Role with name AWSDataLifecycleManagerDefaultRole already exists` 错误，请参阅 [排查 Amazon Data Lifecycle Manager 问题](dlm-troubleshooting.md) 来了解更多信息。

------
#### [ Command line ]

使用[create-lifecycle-policy](https://docs.aws.amazon.com/cli/latest/reference/dlm/create-lifecycle-policy.html)命令创建快照生命周期策略。对于 `PolicyType`，请指定 `EBS_SNAPSHOT_MANAGEMENT`。

**注意**  
为简化语法，以下示例使用包含策略详细信息的 JSON 文件 `policyDetails.json`。

**示例 1 – 具有两个计划的快照生命周期策略**  
此示例创建的快照生命周期策略可创建标签键 `costcenter` 的值为 `115` 的所有卷的快照。该策略包含两个计划。第一个计划在每天 3:00 UTC 创建快照。第二个计划在每周五 17:00 UTC 创建一个周快照。

```
aws dlm create-lifecycle-policy \
    --description "My volume policy" \
    --state ENABLED \
    --execution-role-arn arn:aws:iam::12345678910:role/AWSDataLifecycleManagerDefaultRole \
    --policy-details file://policyDetails.json
```

以下是 `policyDetails.json` 文件的示例。

```
{
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "ResourceTypes": [
        "VOLUME"
    ],
    "TargetTags": [{
        "Key": "costcenter",
        "Value": "115"
    }],
    "Schedules": [{
        "Name": "DailySnapshots",
        "TagsToAdd": [{
            "Key": "type",
            "Value": "myDailySnapshot"
        }],
        "CreateRule": {
            "Interval": 24,
            "IntervalUnit": "HOURS",
            "Times": [
                "03:00"
            ]
        },
        "RetainRule": {
            "Count": 5
        },
        "CopyTags": false
    },
    {
        "Name": "WeeklySnapshots",
        "TagsToAdd": [{
            "Key": "type",
            "Value": "myWeeklySnapshot"
        }],
        "CreateRule": {
            "CronExpression": "cron(0 17 ? * FRI *)"
        },
        "RetainRule": {
            "Count": 5
        },
        "CopyTags": false
    }
]}
```

如果请求成功，此命令将返回新创建的策略 ID。下面是示例输出。

```
{
   "PolicyId": "policy-0123456789abcdef0"
}
```

**示例 2：以实例为目标并创建数据（非根）卷子集快照的快照生命周期策略**  
此示例创建的快照生命周期策略可从标记为 `code=production` 的实例创建多卷快照集。该策略仅包含一个计划。该计划不会创建标记为 `code=temp` 的数据卷的快照。

```
aws dlm create-lifecycle-policy \
    --description "My volume policy" \
    --state ENABLED \
    --execution-role-arn arn:aws:iam::12345678910:role/AWSDataLifecycleManagerDefaultRole \
    --policy-details file://policyDetails.json
```

以下是 `policyDetails.json` 文件的示例。

```
{
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "ResourceTypes": [
        "INSTANCE"
    ],
    "TargetTags": [{
        "Key": "code",
        "Value": "production"
    }],
    "Parameters": {
        "ExcludeDataVolumeTags": [{
            "Key": "code",
            "Value": "temp"
        }]
    },
    "Schedules": [{
        "Name": "DailySnapshots",
        "TagsToAdd": [{
            "Key": "type",
            "Value": "myDailySnapshot"
        }],
        "CreateRule": {
            "Interval": 24,
            "IntervalUnit": "HOURS",
            "Times": [
                "03:00"
            ]
        },
        "RetainRule": {
            "Count": 5
        },
        "CopyTags": false
    }
]}
```

如果请求成功，此命令将返回新创建的策略 ID。下面是示例输出。

```
{
   "PolicyId": "policy-0123456789abcdef0"
}
```

**示例 3：自动执行 Outpost 资源本地快照的快照生命周期策略**  
此示例创建一个快照生命周期策略，该策略创建所有 Outposts 中带有 `team=dev` 标记的卷的快照。该策略在源卷所在的同一 Outposts 上创建快照。该策略从 `12` UTC 开始每 `00:00` 小时创建一次快照。

```
aws dlm create-lifecycle-policy \
    --description "My local snapshot policy" \
    --state ENABLED \
    --execution-role-arn arn:aws:iam::12345678910:role/AWSDataLifecycleManagerDefaultRole \
    --policy-details file://policyDetails.json
```

以下是 `policyDetails.json` 文件的示例。

```
{
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "ResourceTypes": "VOLUME",
	"ResourceLocations": "OUTPOST",
    "TargetTags": [{
        "Key": "team",
        "Value": "dev"
    }],
    "Schedules": [{
        "Name": "on-site backup",
        "CreateRule": {
            "Interval": 12,
            "IntervalUnit": "HOURS",
            "Times": [
                "00:00"
            ],
	"Location": [
		"OUTPOST_LOCAL"
	]
        },
        "RetainRule": {
            "Count": 1
        },
        "CopyTags": false
    }
]}
```

**示例 4：在区域中创建快照并将其复制到 Outpost 的快照生命周期策略**  
以下示例策略创建带 `team=dev` 标记的卷的快照。快照在源卷所在的同一区域中创建。从 `12` UTC 开始，每 `00:00` 小时创建一次快照，并保留最多 `1` 个快照。该策略还会将快照复制到 Outpost `arn:aws:outposts:us-east-1:123456789012:outpost/op-1234567890abcdef0`，使用默认加密 KMS 密钥 对复制的快照进行加密，并将副本保留 `1` 个月。

```
aws dlm create-lifecycle-policy \
    --description "Copy snapshots to Outpost" \
    --state ENABLED \
    --execution-role-arn arn:aws:iam::12345678910:role/AWSDataLifecycleManagerDefaultRole \
    --policy-details file://policyDetails.json
```

以下是 `policyDetails.json` 文件的示例。

```
{
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "ResourceTypes": "VOLUME",
    "ResourceLocations": "CLOUD",
    "TargetTags": [{
        "Key": "team",
        "Value": "dev"
    }],
    "Schedules": [{
        "Name": "on-site backup",
        "CopyTags": false,
        "CreateRule": {
            "Interval": 12,
            "IntervalUnit": "HOURS",
            "Times": [
                "00:00"
            ],
            "Location": "CLOUD"
        },
        "RetainRule": {
            "Count": 1
        },
        "CrossRegionCopyRules" : [
        {
            "Target": "arn:aws:outposts:us-east-1:123456789012:outpost/op-1234567890abcdef0",
            "Encrypted": true,
            "CopyTags": true,
            "RetainRule": {
                "Interval": 1,
                "IntervalUnit": "MONTHS"
            }
        }]
    }
]}
```

**示例 5 – 快照生命周期策略，具有已启用归档并基于期限的计划**  
此示例将创建一个以带有 `Name=Prod` 标签的卷为目标的快照生命周期策略。此策略采用基于期限的计划，该计划会在每月第一天 09:00 创建快照。此计划会在标准层中将每个快照保留一天，之后将其转移到至存档层。快照在存档层中存储 90 天后将被删除。

```
aws dlm create-lifecycle-policy \
    --description "Copy snapshots to Outpost" \
    --state ENABLED \
    --execution-role-arn arn:aws:iam::12345678910:role/AWSDataLifecycleManagerDefaultRole \
    --policy-details file://policyDetails.json
```

以下是 `policyDetails.json` 文件的示例。

```
{
    "ResourceTypes": [ "VOLUME"],
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "Schedules" : [
      {
        "Name": "sched1",
        "TagsToAdd": [
          {"Key":"createdby","Value":"dlm"}
        ],
        "CreateRule": {
          "CronExpression": "cron(0 9 1 * ? *)"
        },
        "CopyTags": true,
        "RetainRule":{
          "Interval": 1,
          "IntervalUnit": "DAYS"
        },
        "ArchiveRule": {
            "RetainRule":{
              "RetentionArchiveTier": {
                 "Interval": 90,
                 "IntervalUnit": "DAYS"
              }
            }
        }
      }
    ],
    "TargetTags": [
      {
        "Key": "Name",
        "Value": "Prod"
      }
    ]
}
```

**示例 6 – 快照生命周期策略，具有已启用归档并基于计数的计划**  
此示例将创建一个以带有 `Purpose=Test` 标签的卷为目标的快照生命周期策略。此策略采用基于计数的计划，该计划会在每月第一天 09:00 创建快照。此计划将在快照创建后立即将其存档，并在存档层中最多保留三个快照。

```
aws dlm create-lifecycle-policy \
    --description "Copy snapshots to Outpost" \
    --state ENABLED \
    --execution-role-arn arn:aws:iam::12345678910:role/AWSDataLifecycleManagerDefaultRole \
    --policy-details file://policyDetails.json
```

以下是 `policyDetails.json` 文件的示例。

```
{
    "ResourceTypes": [ "VOLUME"],
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "Schedules" : [
      {
        "Name": "sched1",
        "TagsToAdd": [
          {"Key":"createdby","Value":"dlm"}
        ],
        "CreateRule": {
          "CronExpression": "cron(0 9 1 * ? *)"
        },
        "CopyTags": true,
        "RetainRule":{
          "Count": 0
        },
        "ArchiveRule": {
            "RetainRule":{
              "RetentionArchiveTier": {
                 "Count": 3
              }
            }
        }
      }
    ],
    "TargetTags": [
      {
        "Key": "Purpose",
        "Value": "Test"
      }
    ]
}
```

------

## 快照生命周期策略的注意事项
<a name="snapshot-considerations"></a>

以下**一般注意事项**适用于快照生命周期策略：
+ 快照生命周期策略仅针对与策略位于同一区域的实例或卷。
+ 第一个快照创建操作将在指定的开始时间后一小时内开始。后续快照创建操作将在计划时间的一小时内开始。
+ 您可以创建多个策略来备份卷或实例。例如，假设一个卷有两个标签，其中标签 *A* 是每 12 小时创建一次快照的策略 *A* 的目标，标签 *B* 是每 24 小时创建一次快照的策略 *B* 的目标，则 Amazon Data Lifecycle Manager 将根据这两个策略的计划创建快照。或者，您可以通过创建包含多个计划的单个策略来实现相同的结果。例如，您可以创建仅针对标签 *A* 的单个策略，并指定两个计划，以分别用于每 12 小时和每 24 小时一次的策略。
+ 目标资源标签区分大小写。
+ 如果从策略所针对的资源中删除目标标签，则 Amazon Data Lifecycle Manager 不再管理标准层和存档层中的现有快照；如不再需要，您必须手动将其删除。
+ 如果您创建了以实例为目标的策略，并且在创建策略后将新卷挂载到目标实例，则在下次运行策略时，新添加的卷将包含在备份中。策略运行时挂载到实例的所有卷都包括在内。
+ 如果您创建了具有基于 cron 的自定义计划的策略，并且配置为仅创建一个快照，则该策略不会在达到保留阈值时自动删除该快照。如果不再需要快照，则必须手动删除该快照。
+ 如果您创建基于存在时间的策略，其保留期短于创建频率，Amazon Data Lifecycle Manager 将始终保留最后一张快照，直到创建下一张快照。例如，如果基于存在时间的策略每月创建一个快照，保留期为七天，则 Amazon Data Lifecycle Manager 会将每个快照保留一个月，即使保留期为七天。

**[共享快照](snapshot-archive.md)**时需考虑以下事项：
+ 您只能为将卷作为目标的快照策略启用快照存档。
+ 对于每个策略，您只能为一个计划指定一个存档规则。
+ 如果您使用控制台，则只有在创建频率为每月或每年，或者指定一个创建频率至少为 28 天的 cron 表达式时，才能启用快照存档。

  如果您使用的是 AWS CLI、 AWS API 或 AWS SDK，则只有在计划中包含创建频率至少为 28 天的 cron 表达式时，才能启用快照存档。
+ 存档层中的最短保留期为 90 天。
+ 快照存档时，快照将在移动到存档层时转换为完整快照。这可能会导致快照存储成本增加。有关更多信息，请参阅 [归档 Amazon EBS 快照的定价和计费](snapshot-archive-pricing.md)。
+ 快照存档时将会禁用快速快照还原和快照共享。
+ 如果在某个闰年中，您的保留规则导致存档保留期少于 90 天，则 Amazon Data Lifecycle Manager 会确保快照至少保留 90 天。
+ 如果您手动将 Amazon Data Lifecycle Manager 创建的快照存档，并且该快照在达到计划的保留阈值时仍在存档，则 Amazon Data Lifecycle Manager 将不再管理该快照。但是，如果您在达到计划的保留阈值之前将快照还原到标准层，则该计划将继续按照保留规则管理快照。
+ 如果您将 Amazon Data Lifecycle Manager 创建的快照永久或临时还原到标准层，并且该快照在达到计划的保留阈值时仍处于标准层中，则 Amazon Data Lifecycle Manager 将不再管理该快照。但是，如果您在达到计划的保留阈值之前重新将快照存档，则计划将在达到保留阈值时删除快照。
+ Amazon Data Lifecycle Manager 存档的快照会使用您的 `Archived snapshots per volume` 和 `In-progress snapshot archives per account` 限额。
+ 如果计划在重试 24 小时后仍无法将快照存档，则该快照将保留在标准层中，并按照本应从存档层中删除的时间来计划删除时间。例如，假设计划将快照存档 120 天，则在存档失败后，快照会保留在标准层中 120 天，然后才会被永久删除。对于基于计数的计划，快照不会计入计划的保留计数。
+ 快照存档的区域必须与创建快照的区域相同。如果您启用了跨区域复制和快照存档，Amazon Data Lifecycle Manager 不会将快照副本存档。
+ Amazon Data Lifecycle Manager 存档的快照将会使用 `aws:dlm:archived=true` 系统标签进行标记。此外，如果创建快照的计划已启用存档并且基于期限，则将会使用 `aws:dlm:expirationTime` 系统标签标记所创建的快照，以注明计划将快照存档的日期和时间。

以下注意事项适用于**排除根卷和数据（非根）卷**：
+ 如果您选择排除启动卷，并且指定的标签因此排除所有附加到实例的额外数据卷，那么 Amazon Data Lifecycle Manager 将不会为受影响的实例创建任何快照，而是会发布一个`SnapshotsCreateFailed`CloudWatch 指标。有关更多信息，请参阅 [使用监控策略 CloudWatch](monitor-dlm-cw-metrics.md)。

**删除或终止快照生命周期策略用作目标的卷或实例**时应注意以下事项：
+ 对于具有基于计数的保留计划的策略用作目标的卷或实例，如果您将该卷删除或将该实例终止，则 Amazon Data Lifecycle Manager 将不再管理标准层和存档层中之前从已删除的卷或已终止的实例创建的快照。如果不再需要较早版本的快照，您必须手动将其删除。
+ 对于具有基于期限的保留计划的策略用作目标的卷或实例，如果您将该卷删除或将该实例终止，则该策略将继续按照既定计划从标准层和存档层中删除从已删除的卷或实例创建的快照，直到但不包括最后一个快照。如果不再需要最后一个快照，则必须手动删除该快照。

快照生命周期策略和**[快速快照还原](ebs-fast-snapshot-restore.md)**应注意以下事项：
+ Amazon Data Lifecycle Manager 只能为大小为 16 TiB 或以下的快照启用快速快照还原。有关更多信息，请参阅 [Amazon EBS 快速快照还原](ebs-fast-snapshot-restore.md)。
+ 即使您删除或禁用了策略，为该策略禁用了快速快照还原，或者为该可用区禁用了快速快照还原，已启用快速快照还原的快照仍会保持启用状态。您必须手动为这些快照禁用快速快照还原。
+ 如果您为策略启用了快速快照还原，并且超出了可启用快速快照还原的最大快照数，Amazon Data Lifecycle Manager 将按计划创建快照，但不会为其启用快速快照还原。在删除启用了快速快照还原的快照后，将为 Amazon Data Lifecycle Manager 创建的下一个快照启用快速快照还原。
+ 快照启用快速快照还原后，每 TiB 需要 60 分钟来优化快照。我们建议您配置相应的计划，以确保在 Amazon Data Lifecycle Manager 创建下一个快照之前对每个快照进行完全优化。
+ 如果您为以实例为目标的策略启用快速快照还原，Amazon Data Lifecycle Manager 会为多卷快照集中的各个快照单独启用快速快照还原。如果 Amazon Data Lifecycle Manager 无法为多卷快照集中的其中一个快照启用快速快照还原，它仍会尝试为快照集中的其余快照启用快速快照还原。
+ 对于为特定可用区中快照启用的快速快照还原，您需要按每分钟支付费用。收费按比例计算，最少 1 小时。有关更多信息，请参阅 [定价和计费](ebs-fast-snapshot-restore.md#fsr-pricing)。
**注意**  
根据生命周期策略的配置，您可以在多个可用区同时为多个快照启用快速快照还原。

快照生命周期策略和**启用[多重挂载](ebs-volumes-multi.md)的卷**应注意以下事项：
+ 如果创建的生命周期策略以启用了多重挂载的卷为目标实例，则 Amazon Data Lifecycle Manager 将为每个挂载的实例启动卷的快照。使用*时间戳*标签来标识从附加实例创建的时间一致的快照集。

**跨账户共享快照**时需注意以下事项：
+ 您只能共享未加密的快照或使用 客户托管密钥 加密的快照。
+ 您无法共享使用默认 EBS 加密 KMS 密钥 加密的快照。
+ 如果您共享加密快照，则还必须与目标账户共享用于加密源卷的 KMS 密钥。有关更多信息，请参阅《AWS Key Management Service 开发人员指南》**中的 [Allowing users in other accounts to use a KMS key](https://docs.aws.amazon.com//kms/latest/developerguide/key-policy-modifying-external-accounts.html)。

快照策略和**[快照归档](snapshot-archive.md)**应注意以下事项：
+ 如果您手动归档由策略创建的快照，并且该快照在达到策略的保留阈值时位于归档层中，则 Amazon Data Lifecycle Manager 将不会删除该快照。当快照存储在归档层中时，Amazon Data Lifecycle Manager 不管理快照。如果您不再需要存储在归档层中的快照，则必须手动将其删除。

以下注意事项适用于快照策略和[回收站](recycle-bin.md)：
+ 如果 Amazon Data Lifecycle Manager 删除快照并在达到策略的保留阈值时将其发送到回收站，并且您从回收站手动还原快照，则必须在不再需要该快照时手动删除它。Amazon Data Lifecycle Manager 将不再管理该快照。
+ 如果您手动删除由策略创建的快照，并且该快照在达到策略的保留阈值时位于回收站中，则 Amazon Data Lifecycle Manager 将不会删除该快照。当快照存储在回收站中时，Amazon Data Lifecycle Manager 不管理快照。

  如果在达到策略的保留阈值之前从回收站还原了快照，那么当达到策略的保留阈值时，Amazon Data Lifecycle Manager 将删除快照。

  如果在达到策略的保留阈值之前从回收站还原了快照，则 Amazon Data Lifecycle Manager 将不再删除快照。如果不再需要快照，则必须手动删除该快照。

以下注意事项适用于处于 **error**（错误）状态的快照生命周期策略：
+ 对于具有基于存在时间的保留计划的策略，则设置为在策略处于 `error` 状态时过期的快照将无限期保留。您必须手动删除快照。重新启用该策略时，Amazon Data Lifecycle Manager 会在其保留期限到期时恢复删除快照。
+ 对于具有基于计数的保留计划的策略，策略会在其处于 `error` 状态时停止创建和删除快照。当您重新启用该策略时，Amazon Data Lifecycle Manager 将恢复创建快照，并在达到保留阈值时恢复删除快照。

快照策略和**[快照锁定](ebs-snapshot-lock.md)**应注意以下事项：
+ 如果您手动锁定由 Amazon Data Lifecycle Manager 创建的快照，并且在达到计划的保留阈值时该快照仍处于锁定状态，则 Amazon Data Lifecycle Manager 将不再管理该快照。如果不再需要快照，则必须手动删除该快照。
+ 如果您手动锁定由 Amazon Data Lifecycle Manager 创建并启用了“快速快照还原”功能的快照，并且在达到保留阈值时该快照仍处于锁定状态，则 Amazon Data Lifecycle Manager 将不会禁用“快速快照还原”功能或删除该快照。如果不再需要快照，则必须手动禁用“快速快照还原”功能并删除该快照。
+ 如果您手动将 Amazon Data Lifecycle Manager 创建的快照注册到 AMI，然后锁定该快照，并且在达到保留阈值时该快照仍处于锁定状态并与 AMI 关联，则 Amazon Data Lifecycle Manager 将继续尝试删除该快照。当 AMI 取消注册并解锁快照时，Amazon Data Lifecycle Manager 将自动删除该快照。

## 其他资源
<a name="snapshot-additional-resources"></a>

有关更多信息，请参阅[使用 Amazon Data Lifecycle Manager AWS 存储自动化 Amazon EBS 快照和 AMI 管理](https://aws.amazon.com/blogs/storage/automating-amazon-ebs-snapshot-and-ami-management-using-amazon-dlm/)博客。

# 使用 Data Lifecycle Manager 自动生成应用程序一致性快照
<a name="automate-app-consistent-backups"></a>

您可以通过在以实例为目标的快照生命周期策略中启用前置和后置脚本，使用 Amazon Data Lifecycle Manager 自动生成应用程序一致性快照。

Amazon Data Lifecycle Manager 与 AWS Systems Manager （Systems Manager）集成，以支持应用程序一致性快照。Amazon Data Lifecycle Manager 使用 Systems Manager（SSM）命令文档（包括前置和后置脚本）来自动执行完成应用程序一致性快照所需的操作。在 Amazon Data Lifecycle Manager 启动快照创建之前，它会运行预脚本中的命令进行冻结和刷新I/O. After Amazon Data Lifecycle Manager initiates snapshot creation, it runs the commands in the post script to thaw I/O。

使用 Amazon Data Lifecycle Manager，您可以自动生成以下内容的应用程序一致性快照：
+ 使用卷影复制服务（VSS）的 Windows 应用程序
+ SAP HANA 使用 AWS 托管 SSDM 文档。有关更多信息，请参阅 [Amazon EBS snapshots for SAP HANA](https://docs.aws.amazon.com/sap/latest/sap-hana/ebs-sap-hana.html)。
+ 使用 SSM 文档模板自行管理的数据库，例如 MySQL、PostgreSQL InterSystems 或 IRIS

**Topics**
+ [使用前置和后置脚本的要求](#app-consistent-prereqs)
+ [应用程序一致性快照入门](#app-consistent-get-started)
+ [使用 Amazon Data Lifecycle Manager 进行 VSS 备份的注意事项](#app-consistent-vss)
+ [应用程序一致性快照的共同责任](#shared-responsibility)

## 使用前置和后置脚本的要求
<a name="app-consistent-prereqs"></a>

下表概述了将前置和后置脚本与 Amazon Data Lifecycle Manager 一起使用的要求。


|  | 应用程序一致性快照 |  | 
| --- |--- |--- |
| 要求 | VSS 备份 | 自定义 SSM 文档 | 其他用例 | 
| --- |--- |--- |--- |
| SSM 代理已安装并在目标实例上运行 | ✓ | ✓ | ✓ | 
| 目标实例已满足 VSS 系统要求 | ✓ |  |  | 
| 与目标实例关联的启用 VSS 的实例配置文件 | ✓ |  |  | 
| 安装在目标实例上的 VSS 组件 | ✓ |  |  | 
| 使用脚本前和后置脚本命令准备 SSM 文档 |  | ✓ | ✓ | 
| 准备 Amazon Data Lifecycle Manager IAM 角色运行前和发布脚本 | ✓ | ✓ | ✓ | 
| 创建以实例为目标的快照策略，并针对前脚本和后脚本进行配置 | ✓ | ✓ | ✓ | 

## 应用程序一致性快照入门
<a name="app-consistent-get-started"></a>

本节介绍使用 Amazon Data Lifecycle Manager 自动生成应用程序一致性快照所需遵循的步骤。

### 步骤 1：准备目标实例
<a name="prep-instances"></a>

您需要使用 Amazon Data Lifecycle Manager 为应用程序一致性快照准备目标实例。根据您的用例执行以下操作之一。

------
#### [ Prepare for VSS Backups ]

**为 VSS 备份准备目标实例**

1. 在目标实例上安装 SSM Agent（如果尚未安装）。如果目标实例上已安装 SSM Agent，请跳过此步骤。

   有关更多信息，请参阅[在适用于 Windows Server 的 EC2 实例上使用 SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-windows.html)。

1. 确保 SSM Agent 正在运行。有关更多信息，请参阅[正在检查 SSM Agent 状态并启动代理](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-status-and-restart.html)。

1. 为 Amazon EC2 实例设置 Systems Manager。有关更多信息，请参阅《AWS Systems Manager 用户指南》**中的[为 Amazon EC2 实例设置 Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-setting-up-ec2.html)。

1. [确保满足 VSS 备份的系统要求](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/application-consistent-snapshots-prereqs.html)。

1. [将启用 VSS 的实例配置文件附加到目标实例](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/vss-iam-reqs.html)。

1. [安装 VSS 组件](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/application-consistent-snapshots-getting-started.html)。

------
#### [ Prepare for SAP HANA backups ]

**为 SAP HANA 备份准备目标实例**

1. 在目标实例上准备 SAP HANA 环境。

   1. 使用 SAP HANA 设置实例。如果您还没有现成的 SAP HANA 环境，则可以参考 [SAP HANA Environment Setup on AWS](https://docs.aws.amazon.com/sap/latest/sap-hana/std-sap-hana-environment-setup.html)。

   1. 以合适的管理员用户身份登录 SystemDB。

   1. 创建要与 Amazon Data Lifecycle Manager 一起使用的数据库备份用户。

      ```
      CREATE USER username PASSWORD password NO FORCE_FIRST_PASSWORD_CHANGE;
      ```

      例如，以下命令创建了一个名为 `dlm_user` 并且密码为 `password` 的用户。

      ```
      CREATE USER dlm_user PASSWORD password NO FORCE_FIRST_PASSWORD_CHANGE;
      ```

   1. 将 `BACKUP OPERATOR` 角色分配给您在上一步中创建的数据库备份用户。

      ```
      GRANT BACKUP OPERATOR TO username
      ```

      例如，以下命令将角色分配给名为 `dlm_user` 的用户。

      ```
      GRANT BACKUP OPERATOR TO dlm_user
      ```

   1. 以管理员身份登录操作系统，例如 `sidadm`。

   1. 创建一个 `hdbuserstore` 条目来存储连接信息，这样 SAP HANA SSM 文档就可以连接到 SAP HANA，而无需用户输入信息。

      ```
      hdbuserstore set DLM_HANADB_SNAPSHOT_USER localhost:3hana_instance_number13 username password
      ```

      例如：

      ```
      hdbuserstore set DLM_HANADB_SNAPSHOT_USER localhost:30013 dlm_user password
      ```

   1. 测试连接。

      ```
      hdbsql -U DLM_HANADB_SNAPSHOT_USER "select * from dummy"
      ```

1. 在目标实例上安装 SSM Agent（如果尚未安装）。如果目标实例上已安装 SSM Agent，请跳过此步骤。

   有关更多信息，请参阅[在 Linux EC2 实例上手动安装 SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/manually-install-ssm-agent-linux.html)。

1. 确保 SSM Agent 正在运行。有关更多信息，请参阅[正在检查 SSM Agent 状态并启动代理](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-status-and-restart.html)。

1. 为 Amazon EC2 实例设置 Systems Manager。有关更多信息，请参阅《AWS Systems Manager 用户指南》**中的[为 Amazon EC2 实例设置 Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-setting-up-ec2.html)。

------
#### [ Prepare for custom SSM documents ]

**为 SSM 文档准备目标实例**

1. 在目标实例上安装 SSM Agent（如果尚未安装）。如果目标实例上已安装 SSM Agent，请跳过此步骤。
   + （Linux 实例）[在适用于 Linux 的 EC2 实例上手动安装 SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/manually-install-ssm-agent-linux.html)
   + （Windows 实例）[在适用于 Windows 的 EC2 实例上手动安装 SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-windows.html)

1. 确保 SSM Agent 正在运行。有关更多信息，请参阅[正在检查 SSM Agent 状态并启动代理](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-status-and-restart.html)。

1. 为 Amazon EC2 实例设置 Systems Manager。有关更多信息，请参阅《AWS Systems Manager 用户指南》**中的[为 Amazon EC2 实例设置 Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-setting-up-ec2.html)。

------

### 步骤 2：准备 SSM 文档
<a name="prep-ssm-doc"></a>

**注意**  
只有自定义 SSM 文档才需要执行此步骤。VSS 备份或 SAP HANA 不需要执行此步骤。对于 VSS 备份和 SAP HANA，Amazon Data Lifecycle Manager 使用 AWS 托管 SSM 文档。

如果要为自管理的数据库（例如 MySQL、PostgreSQL 或 InterSystems IRIS）自动生成应用程序一致性快照，则必须创建一个 SSM 命令文档，其中包含用于在启动快照创建 I/O 之前冻结和刷新的预脚本，以及启动快照创建后解冻的后置脚本。 I/O 

如果您的 MySQL、PostgreSQL InterSystems 或 IRIS 数据库使用标准配置，则可以使用下面的示例 SSM 文档内容创建 SSM 命令文档。如果您的 MySQL、PostgreSQL InterSystems 或 IRIS 数据库使用非标准配置，则可以使用以下示例内容作为 SSM 命令文档的起点，然后对其进行自定义以满足您的要求。或者，如果想要从头开始创建新的 SSM 文档，则可以使用下面的 SSM 文档空白模板，并在相应的文档部分中添加前置和后置命令。

**注意以下几点：**  
您负责确保 SSM 文档为数据库配置执行正确且必需的操作。
只有当 SSM 文档中的前置和后置脚本能够成功冻结、刷新和解冻 I/O 时，才能保证快照具有应用程序一致性。
SSM 文档必须包含 `allowedValues` 的必填字段，包括 `pre-script`、`post-script` 和 `dry-run`。Amazon Data Lifecycle Manager 将根据这些部分的内容在您的实例上执行命令。如果您的 SSM 文档没有这些部分，则 Amazon Data Lifecycle Manager 会将其视为执行失败。

------
#### [ MySQL sample document content ]

```
###===============================================================================###
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
###===============================================================================###
schemaVersion: '2.2'
description: Amazon Data Lifecycle Manager Pre/Post script for MySQL databases
parameters:
  executionId:
    type: String
    default: None
    description: (Required) Specifies the unique identifier associated with a pre and/or post execution
    allowedPattern: ^(None|[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$
  command:
  # Data Lifecycle Manager will trigger the pre-script and post-script actions during policy execution. 
  # 'dry-run' option is intended for validating the document execution without triggering any commands
  # on the instance. The following allowedValues will allow Data Lifecycle Manager to successfully 
  # trigger pre and post script actions.
    type: String
    default: 'dry-run'
    description: (Required) Specifies whether pre-script and/or post-script should be executed.
    allowedValues:
    - pre-script
    - post-script
    - dry-run

mainSteps:
- action: aws:runShellScript
  description: Run MySQL Database freeze/thaw commands
  name: run_pre_post_scripts
  precondition:
    StringEquals:
    - platformType
    - Linux
  inputs:
    runCommand:
    - |
      #!/bin/bash

      ###===============================================================================###
      ### Error Codes
      ###===============================================================================###
      # The following Error codes will inform Data Lifecycle Manager of the type of error 
      # and help guide handling of the error. 
      # The Error code will also be emitted via AWS Eventbridge events in the 'cause' field.
      # 1 Pre-script failed during execution - 201
      # 2 Post-script failed during execution - 202
      # 3 Auto thaw occurred before post-script was initiated - 203
      # 4 Pre-script initiated while post-script was expected - 204
      # 5 Post-script initiated while pre-script was expected - 205
      # 6 Application not ready for pre or post-script initiation - 206

      ###=================================================================###
      ### Global variables
      ###=================================================================###
      START=$(date +%s)
      # For testing this script locally, replace the below with OPERATION=$1.
      OPERATION={{ command }}
      FS_ALREADY_FROZEN_ERROR='freeze failed: Device or resource busy'
      FS_ALREADY_THAWED_ERROR='unfreeze failed: Invalid argument'
      FS_BUSY_ERROR='mount point is busy'

      # Auto thaw is a fail safe mechanism to automatically unfreeze the application after the 
      # duration specified in the global variable below. Choose the duration based on your
      # database application's tolerance to freeze.
      export AUTO_THAW_DURATION_SECS="60"

      # Add all pre-script actions to be performed within the function below
      execute_pre_script() {
          echo "INFO: Start execution of pre-script"
          # Check if filesystem is already frozen. No error code indicates that filesystem 
          # is not currently frozen and that the pre-script can proceed with freezing the filesystem.
          check_fs_freeze
          # Execute the DB commands to flush the DB in preparation for snapshot
          snap_db
          # Freeze the filesystem. No error code indicates that filesystem was succefully frozen
          freeze_fs

          echo "INFO: Schedule Auto Thaw to execute in ${AUTO_THAW_DURATION_SECS} seconds."
          $(nohup bash -c execute_schedule_auto_thaw  >/dev/null 2>&1 &)
      }

      # Add all post-script actions to be performed within the function below
      execute_post_script() {
          echo "INFO: Start execution of post-script"
          # Unfreeze the filesystem. No error code indicates that filesystem was successfully unfrozen.
          unfreeze_fs
          thaw_db
      }

      # Execute Auto Thaw to automatically unfreeze the application after the duration configured 
      # in the AUTO_THAW_DURATION_SECS global variable.
      execute_schedule_auto_thaw() {
          sleep ${AUTO_THAW_DURATION_SECS}
          execute_post_script
      }

      # Disable Auto Thaw if it is still enabled
      execute_disable_auto_thaw() {
          echo "INFO: Attempting to disable auto thaw if enabled"
          auto_thaw_pgid=$(pgrep -f execute_schedule_auto_thaw | xargs -i ps -hp {} -o pgid)
          if [ -n "${auto_thaw_pgid}" ]; then
              echo "INFO: execute_schedule_auto_thaw process found with pgid ${auto_thaw_pgid}"
              sudo pkill -g ${auto_thaw_pgid}
              rc=$?
              if [ ${rc} != 0 ]; then
                  echo "ERROR: Unable to kill execute_schedule_auto_thaw process. retval=${rc}"
              else
                  echo "INFO: Auto Thaw  has been disabled"
              fi
          fi
      }

      # Iterate over all the mountpoints and check if filesystem is already in freeze state.
      # Return error code 204 if any of the mount points are already frozen.
      check_fs_freeze() {
          for target in $(lsblk -nlo MOUNTPOINTS)
          do
              # Freeze of the root and boot filesystems is dangerous and pre-script does not freeze these filesystems.
              # Hence, we will skip the root and boot mountpoints while checking if filesystem is in freeze state.
              if [ $target == '/' ]; then continue; fi
              if [[ "$target" == *"/boot"* ]]; then continue; fi

              error_message=$(sudo mount -o remount,noatime $target 2>&1)
              # Remount will be a no-op without a error message if the filesystem is unfrozen.
              # However, if filesystem is already frozen, remount will fail with busy error message.
              if [ $? -ne 0 ];then
                  # If the filesystem is already in frozen, return error code 204
                  if [[ "$error_message" == *"$FS_BUSY_ERROR"* ]];then
                      echo "ERROR: Filesystem ${target} already frozen. Return Error Code: 204"
                      exit 204
                  fi
                  # If the check filesystem freeze failed due to any reason other than the filesystem already frozen, return 201
                  echo "ERROR: Failed to check_fs_freeze on mountpoint $target due to error - $errormessage"
                  exit 201
              fi
          done
      } 

      # Iterate over all the mountpoints and freeze the filesystem.
      freeze_fs() {
          for target in $(lsblk -nlo MOUNTPOINTS)
          do
              # Freeze of the root and boot filesystems is dangerous. Hence, skip filesystem freeze 
              # operations for root and boot mountpoints.
              if [ $target == '/' ]; then continue; fi
              if [[ "$target" == *"/boot"* ]]; then continue; fi
              echo "INFO: Freezing $target"
              error_message=$(sudo fsfreeze -f $target 2>&1)
              if [ $? -ne 0 ];then
                  # If the filesystem is already in frozen, return error code 204
                  if [[ "$error_message" == *"$FS_ALREADY_FROZEN_ERROR"* ]]; then
                      echo "ERROR: Filesystem ${target} already frozen. Return Error Code: 204"
                      sudo mysql -e 'UNLOCK TABLES;'
                      exit 204
                  fi
                  # If the filesystem freeze failed due to any reason other than the filesystem already frozen, return 201
                  echo "ERROR: Failed to freeze mountpoint $targetdue due to error - $errormessage"
                  thaw_db
                  exit 201
              fi
              echo "INFO: Freezing complete on $target"
          done
      }

      # Iterate over all the mountpoints and unfreeze the filesystem.
      unfreeze_fs() {
          for target in $(lsblk -nlo MOUNTPOINTS)
          do
              # Freeze of the root and boot filesystems is dangerous and pre-script does not freeze these filesystems.
              # Hence, will skip the root and boot mountpoints during unfreeze as well.
              if [ $target == '/' ]; then continue; fi
              if [[ "$target" == *"/boot"* ]]; then continue; fi
              echo "INFO: Thawing $target"
              error_message=$(sudo fsfreeze -u $target 2>&1)
              # Check if filesystem is already unfrozen (thawed). Return error code 204 if filesystem is already unfrozen.
              if [ $? -ne 0 ]; then
                  if [[ "$error_message" == *"$FS_ALREADY_THAWED_ERROR"* ]]; then
                      echo "ERROR: Filesystem ${target} is already in thaw state. Return Error Code: 205"
                      exit 205
                  fi
                  # If the filesystem unfreeze failed due to any reason other than the filesystem already unfrozen, return 202
                  echo "ERROR: Failed to unfreeze mountpoint $targetdue due to error - $errormessage"
                  exit 202
              fi
              echo "INFO: Thaw complete on $target"
          done    
      }

      snap_db() {
          # Run the flush command only when MySQL DB service is up and running
          sudo systemctl is-active --quiet mysqld.service
          if [ $? -eq 0 ]; then
              echo "INFO: Execute MySQL Flush and Lock command."
              sudo mysql -e 'FLUSH TABLES WITH READ LOCK;'
              # If the MySQL Flush and Lock command did not succeed, return error code 201 to indicate pre-script failure
              if [ $? -ne 0 ]; then
                  echo "ERROR: MySQL FLUSH TABLES WITH READ LOCK command failed."
                  exit 201
              fi
              sync
          else 
              echo "INFO: MySQL service is inactive. Skipping execution of MySQL Flush and Lock command."
          fi
      }

      thaw_db() {
          # Run the unlock command only when MySQL DB service is up and running
          sudo systemctl is-active --quiet mysqld.service
          if [ $? -eq 0 ]; then
              echo "INFO: Execute MySQL Unlock"
              sudo mysql -e 'UNLOCK TABLES;'
          else 
              echo "INFO: MySQL service is inactive. Skipping execution of MySQL Unlock command."
          fi
      }

      export -f execute_schedule_auto_thaw
      export -f execute_post_script
      export -f unfreeze_fs
      export -f thaw_db

      # Debug logging for parameters passed to the SSM document
      echo "INFO: ${OPERATION} starting at $(date) with executionId: ${EXECUTION_ID}"

      # Based on the command parameter value execute the function that supports 
      # pre-script/post-script operation
      case ${OPERATION} in
          pre-script)
              execute_pre_script
              ;;
          post-script)
              execute_post_script
              execute_disable_auto_thaw
              ;;
          dry-run)
              echo "INFO: dry-run option invoked - taking no action"
              ;;
          *)
              echo "ERROR: Invalid command parameter passed. Please use either pre-script, post-script, dry-run."
              exit 1 # return failure
              ;;
      esac

      END=$(date +%s)
      # Debug Log for profiling the script time
      echo "INFO: ${OPERATION} completed at $(date). Total runtime: $((${END} - ${START})) seconds."
```

------
#### [ PostgreSQL sample document content ]

```
###===============================================================================###
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
###===============================================================================###
schemaVersion: '2.2'
description: Amazon Data Lifecycle Manager Pre/Post script for PostgreSQL databases
parameters:
  executionId:
    type: String
    default: None
    description: (Required) Specifies the unique identifier associated with a pre and/or post execution
    allowedPattern: ^(None|[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$
  command:
  # Data Lifecycle Manager will trigger the pre-script and post-script actions during policy execution. 
  # 'dry-run' option is intended for validating the document execution without triggering any commands
  # on the instance. The following allowedValues will allow Data Lifecycle Manager to successfully 
  # trigger pre and post script actions.
    type: String
    default: 'dry-run'
    description: (Required) Specifies whether pre-script and/or post-script should be executed.
    allowedValues:
    - pre-script
    - post-script
    - dry-run

mainSteps:
- action: aws:runShellScript
  description: Run PostgreSQL Database freeze/thaw commands
  name: run_pre_post_scripts
  precondition:
    StringEquals:
    - platformType
    - Linux
  inputs:
    runCommand:
    - |
      #!/bin/bash

      ###===============================================================================###
      ### Error Codes
      ###===============================================================================###
      # The following Error codes will inform Data Lifecycle Manager of the type of error 
      # and help guide handling of the error. 
      # The Error code will also be emitted via AWS Eventbridge events in the 'cause' field.
      # 1 Pre-script failed during execution - 201
      # 2 Post-script failed during execution - 202
      # 3 Auto thaw occurred before post-script was initiated - 203
      # 4 Pre-script initiated while post-script was expected - 204
      # 5 Post-script initiated while pre-script was expected - 205
      # 6 Application not ready for pre or post-script initiation - 206

      ###===============================================================================###
      ### Global variables
      ###===============================================================================###
      START=$(date +%s)
      OPERATION={{ command }}
      FS_ALREADY_FROZEN_ERROR='freeze failed: Device or resource busy'
      FS_ALREADY_THAWED_ERROR='unfreeze failed: Invalid argument'
      FS_BUSY_ERROR='mount point is busy'

      # Auto thaw is a fail safe mechanism to automatically unfreeze the application after the 
      # duration specified in the global variable below. Choose the duration based on your
      # database application's tolerance to freeze.
      export AUTO_THAW_DURATION_SECS="60"

      # Add all pre-script actions to be performed within the function below
      execute_pre_script() {
          echo "INFO: Start execution of pre-script"
          # Check if filesystem is already frozen. No error code indicates that filesystem 
          # is not currently frozen and that the pre-script can proceed with freezing the filesystem.
          check_fs_freeze
          # Execute the DB commands to flush the DB in preparation for snapshot
          snap_db
          # Freeze the filesystem. No error code indicates that filesystem was succefully frozen
          freeze_fs

          echo "INFO: Schedule Auto Thaw to execute in ${AUTO_THAW_DURATION_SECS} seconds."
          $(nohup bash -c execute_schedule_auto_thaw  >/dev/null 2>&1 &)
      }

      # Add all post-script actions to be performed within the function below
      execute_post_script() {
          echo "INFO: Start execution of post-script"
          # Unfreeze the filesystem. No error code indicates that filesystem was successfully unfrozen
          unfreeze_fs
      }

      # Execute Auto Thaw to automatically unfreeze the application after the duration configured 
      # in the AUTO_THAW_DURATION_SECS global variable.
      execute_schedule_auto_thaw() {
          sleep ${AUTO_THAW_DURATION_SECS}
          execute_post_script
      }

      # Disable Auto Thaw if it is still enabled
      execute_disable_auto_thaw() {
          echo "INFO: Attempting to disable auto thaw if enabled"
          auto_thaw_pgid=$(pgrep -f execute_schedule_auto_thaw | xargs -i ps -hp {} -o pgid)
          if [ -n "${auto_thaw_pgid}" ]; then
              echo "INFO: execute_schedule_auto_thaw process found with pgid ${auto_thaw_pgid}"
              sudo pkill -g ${auto_thaw_pgid}
              rc=$?
              if [ ${rc} != 0 ]; then
                  echo "ERROR: Unable to kill execute_schedule_auto_thaw process. retval=${rc}"
              else
                  echo "INFO: Auto Thaw  has been disabled"
              fi
          fi
      }

      # Iterate over all the mountpoints and check if filesystem is already in freeze state.
      # Return error code 204 if any of the mount points are already frozen.
      check_fs_freeze() {
          for target in $(lsblk -nlo MOUNTPOINTS)
          do
              # Freeze of the root and boot filesystems is dangerous and pre-script does not freeze these filesystems.
              # Hence, we will skip the root and boot mountpoints while checking if filesystem is in freeze state.
              if [ $target == '/' ]; then continue; fi
              if [[ "$target" == *"/boot"* ]]; then continue; fi

              error_message=$(sudo mount -o remount,noatime $target 2>&1)
              # Remount will be a no-op without a error message if the filesystem is unfrozen.
              # However, if filesystem is already frozen, remount will fail with busy error message.
              if [ $? -ne 0 ];then
                  # If the filesystem is already in frozen, return error code 204
                  if [[ "$error_message" == *"$FS_BUSY_ERROR"* ]];then
                      echo "ERROR: Filesystem ${target} already frozen. Return Error Code: 204"
                      exit 204
                  fi
                  # If the check filesystem freeze failed due to any reason other than the filesystem already frozen, return 201
                  echo "ERROR: Failed to check_fs_freeze on mountpoint $target due to error - $errormessage"
                  exit 201
              fi
          done
      } 

      # Iterate over all the mountpoints and freeze the filesystem.
      freeze_fs() {
          for target in $(lsblk -nlo MOUNTPOINTS)
          do
              # Freeze of the root and boot filesystems is dangerous. Hence, skip filesystem freeze 
              # operations for root and boot mountpoints.
              if [ $target == '/' ]; then continue; fi
              if [[ "$target" == *"/boot"* ]]; then continue; fi
              echo "INFO: Freezing $target"
              error_message=$(sudo fsfreeze -f $target 2>&1)
              if [ $? -ne 0 ];then
                  # If the filesystem is already in frozen, return error code 204
                  if [[ "$error_message" == *"$FS_ALREADY_FROZEN_ERROR"* ]]; then
                      echo "ERROR: Filesystem ${target} already frozen. Return Error Code: 204"
                      exit 204
                  fi
                  # If the filesystem freeze failed due to any reason other than the filesystem already frozen, return 201
                  echo "ERROR: Failed to freeze mountpoint $targetdue due to error - $errormessage"
                  exit 201
              fi
              echo "INFO: Freezing complete on $target"
          done
      }

      # Iterate over all the mountpoints and unfreeze the filesystem.
      unfreeze_fs() {
          for target in $(lsblk -nlo MOUNTPOINTS)
          do
              # Freeze of the root and boot filesystems is dangerous and pre-script does not freeze these filesystems.
              # Hence, will skip the root and boot mountpoints during unfreeze as well.
              if [ $target == '/' ]; then continue; fi
              if [[ "$target" == *"/boot"* ]]; then continue; fi
              echo "INFO: Thawing $target"
              error_message=$(sudo fsfreeze -u $target 2>&1)
              # Check if filesystem is already unfrozen (thawed). Return error code 204 if filesystem is already unfrozen.
              if [ $? -ne 0 ]; then
                  if [[ "$error_message" == *"$FS_ALREADY_THAWED_ERROR"* ]]; then
                      echo "ERROR: Filesystem ${target} is already in thaw state. Return Error Code: 205"
                      exit 205
                  fi
                  # If the filesystem unfreeze failed due to any reason other than the filesystem already unfrozen, return 202
                  echo "ERROR: Failed to unfreeze mountpoint $targetdue due to error - $errormessage"
                  exit 202
              fi
              echo "INFO: Thaw complete on $target"
          done
      }

      snap_db() {
          # Run the flush command only when PostgreSQL DB service is up and running
          sudo systemctl is-active --quiet postgresql
          if [ $? -eq 0 ]; then
              echo "INFO: Execute Postgres CHECKPOINT"
              # PostgreSQL command to flush the transactions in memory to disk
              sudo -u postgres psql -c 'CHECKPOINT;'
              # If the PostgreSQL Command did not succeed, return error code 201 to indicate pre-script failure
              if [ $? -ne 0 ]; then
                  echo "ERROR: Postgres CHECKPOINT command failed."
                  exit 201
              fi
              sync
          else 
              echo "INFO: PostgreSQL service is inactive. Skipping execution of CHECKPOINT command."
          fi
      }

      export -f execute_schedule_auto_thaw
      export -f execute_post_script
      export -f unfreeze_fs

      # Debug logging for parameters passed to the SSM document
      echo "INFO: ${OPERATION} starting at $(date) with executionId: ${EXECUTION_ID}"

      # Based on the command parameter value execute the function that supports 
      # pre-script/post-script operation
      case ${OPERATION} in
          pre-script)
              execute_pre_script
              ;;
          post-script)
              execute_post_script
              execute_disable_auto_thaw
              ;;
          dry-run)
              echo "INFO: dry-run option invoked - taking no action"
              ;;
          *)
              echo "ERROR: Invalid command parameter passed. Please use either pre-script, post-script, dry-run."
              exit 1 # return failure
              ;;
      esac

      END=$(date +%s)
      # Debug Log for profiling the script time
      echo "INFO: ${OPERATION} completed at $(date). Total runtime: $((${END} - ${START})) seconds."
```

------
#### [ InterSystems IRIS sample document content ]

```
###===============================================================================###
# MIT License
# 
# Copyright (c) 2024 InterSystems
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
###===============================================================================###
schemaVersion: '2.2'
description: SSM Document Template for Amazon Data Lifecycle Manager Pre/Post script feature for InterSystems IRIS.
parameters:
  executionId:
    type: String
    default: None
    description: Specifies the unique identifier associated with a pre and/or post execution
    allowedPattern: ^(None|[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$
  command:
    type: String
    # Data Lifecycle Manager will trigger the pre-script and post-script actions. You can also use this SSM document with 'dry-run' for manual testing purposes.
    default: 'dry-run'
    description: (Required) Specifies whether pre-script and/or post-script should be executed.
    #The following allowedValues will allow Data Lifecycle Manager to successfully trigger pre and post script actions.
    allowedValues:
    - pre-script
    - post-script
    - dry-run

mainSteps:
- action: aws:runShellScript
  description: Run InterSystems IRIS Database freeze/thaw commands
  name: run_pre_post_scripts
  precondition:
    StringEquals:
    - platformType
    - Linux
  inputs:
    runCommand:
    - |
      #!/bin/bash
      ###===============================================================================###
      ### Global variables
      ###===============================================================================###
      DOCKER_NAME=iris
      LOGDIR=./
      EXIT_CODE=0
      OPERATION={{ command }}
      START=$(date +%s)
      
      # Check if Docker is installed
      # By default if Docker is present, script assumes that InterSystems IRIS is running in Docker
      # Leave only the else block DOCKER_EXEC line, if you run InterSystems IRIS non-containerised (and Docker is present).
      # Script assumes irissys user has OS auth enabled, change the OS user or supply login/password depending on your configuration.
      if command -v docker &> /dev/null
      then
        DOCKER_EXEC="docker exec $DOCKER_NAME"
      else
        DOCKER_EXEC="sudo -i -u irissys"
      fi
      
                    
      # Add all pre-script actions to be performed within the function below
      execute_pre_script() {
        echo "INFO: Start execution of pre-script"
        
        # find all iris running instances
        iris_instances=$($DOCKER_EXEC iris qall 2>/dev/null | tail -n +3 | grep '^up' | cut -c5-  | awk '{print $1}')
        echo "`date`: Running iris instances $iris_instances"
      
        # Only for running instances
        for INST in $iris_instances; do
      
          echo "`date`: Attempting to freeze $INST"
      
          # Detailed instances specific log
          LOGFILE=$LOGDIR/$INST-pre_post.log
          
          #check Freeze status before starting
          $DOCKER_EXEC irissession $INST -U '%SYS' "##Class(Backup.General).IsWDSuspendedExt()"
          freeze_status=$?
          if [ $freeze_status -eq 5 ]; then
            echo "`date`:   ERROR: $INST IS already FROZEN"
            EXIT_CODE=204
          else
            echo "`date`:   $INST is not frozen"
            # Freeze
            # Docs: https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&CLASSNAME=Backup.General#ExternalFreeze
            $DOCKER_EXEC irissession $INST -U '%SYS' "##Class(Backup.General).ExternalFreeze(\"$LOGFILE\",,,,,,600,,,300)"
            status=$?
      
            case $status in
              5) echo "`date`:   $INST IS FROZEN"
                ;;
              3) echo "`date`:   $INST FREEZE FAILED"
                EXIT_CODE=201
                ;;
              *) echo "`date`:   ERROR: Unknown status code: $status"
                EXIT_CODE=201
                ;;
            esac
            echo "`date`:   Completed freeze of $INST"
          fi
        done
        echo "`date`: Pre freeze script finished"
      }
                    
      # Add all post-script actions to be performed within the function below
      execute_post_script() {
        echo "INFO: Start execution of post-script"
      
        # find all iris running instances
        iris_instances=$($DOCKER_EXEC iris qall 2>/dev/null | tail -n +3 | grep '^up' | cut -c5-  | awk '{print $1}')
        echo "`date`: Running iris instances $iris_instances"
      
        # Only for running instances
        for INST in $iris_instances; do
      
          echo "`date`: Attempting to thaw $INST"
      
          # Detailed instances specific log
          LOGFILE=$LOGDIR/$INST-pre_post.log
      
          #check Freeze status befor starting
          $DOCKER_EXEC irissession $INST -U '%SYS' "##Class(Backup.General).IsWDSuspendedExt()"
          freeze_status=$?
          if [ $freeze_status -eq 5 ]; then
            echo "`date`:  $INST is in frozen state"
            # Thaw
            # Docs: https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&CLASSNAME=Backup.General#ExternalFreeze
            $DOCKER_EXEC irissession $INST -U%SYS "##Class(Backup.General).ExternalThaw(\"$LOGFILE\")"
            status=$?
      
            case $status in
              5) echo "`date`:   $INST IS THAWED"
                  $DOCKER_EXEC irissession $INST -U%SYS "##Class(Backup.General).ExternalSetHistory(\"$LOGFILE\")"
                ;;
              3) echo "`date`:   $INST THAW FAILED"
                  EXIT_CODE=202
                ;;
              *) echo "`date`:   ERROR: Unknown status code: $status"
                  EXIT_CODE=202
                ;;
            esac
            echo "`date`:   Completed thaw of $INST"
          else
            echo "`date`:   ERROR: $INST IS already THAWED"
            EXIT_CODE=205
          fi
        done
        echo "`date`: Post thaw script finished"
      }
      
      # Debug logging for parameters passed to the SSM document
        echo "INFO: ${OPERATION} starting at $(date) with executionId: ${EXECUTION_ID}"
                    
      # Based on the command parameter value execute the function that supports 
      # pre-script/post-script operation
      case ${OPERATION} in
        pre-script)
          execute_pre_script
          ;;
        post-script)
          execute_post_script
            ;;
        dry-run)
          echo "INFO: dry-run option invoked - taking no action"
          ;;
        *)
          echo "ERROR: Invalid command parameter passed. Please use either pre-script, post-script, dry-run."
          # return failure
          EXIT_CODE=1
          ;;
      esac
                    
      END=$(date +%s)
      # Debug Log for profiling the script time
      echo "INFO: ${OPERATION} completed at $(date). Total runtime: $((${END} - ${START})) seconds."
      exit $EXIT_CODE
```

有关更多信息，请参阅[GitHub 存储库](https://github.com/intersystems-community/aws/blob/master/README.md)。

------
#### [ Empty document template ]

```
###===============================================================================###
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
###===============================================================================###
schemaVersion: '2.2'
description: SSM Document Template for Amazon Data Lifecycle Manager Pre/Post script feature
parameters:
  executionId:
    type: String
    default: None
    description: (Required) Specifies the unique identifier associated with a pre and/or post execution
    allowedPattern: ^(None|[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$
  command:
  # Data Lifecycle Manager will trigger the pre-script and post-script actions during policy execution. 
  # 'dry-run' option is intended for validating the document execution without triggering any commands
  # on the instance. The following allowedValues will allow Data Lifecycle Manager to successfully 
  # trigger pre and post script actions.
    type: String
    default: 'dry-run'
    description: (Required) Specifies whether pre-script and/or post-script should be executed.
    allowedValues:
    - pre-script
    - post-script
    - dry-run

mainSteps:
- action: aws:runShellScript
  description: Run Database freeze/thaw commands
  name: run_pre_post_scripts
  precondition:
    StringEquals:
    - platformType
    - Linux
  inputs:
    runCommand:
    - |
      #!/bin/bash

      ###===============================================================================###
      ### Error Codes
      ###===============================================================================###
      # The following Error codes will inform Data Lifecycle Manager of the type of error 
      # and help guide handling of the error. 
      # The Error code will also be emitted via AWS Eventbridge events in the 'cause' field.
      # 1 Pre-script failed during execution - 201
      # 2 Post-script failed during execution - 202
      # 3 Auto thaw occurred before post-script was initiated - 203
      # 4 Pre-script initiated while post-script was expected - 204
      # 5 Post-script initiated while pre-script was expected - 205
      # 6 Application not ready for pre or post-script initiation - 206

      ###===============================================================================###
      ### Global variables
      ###===============================================================================###
      START=$(date +%s)
      # For testing this script locally, replace the below with OPERATION=$1.
      OPERATION={{ command }}

      # Add all pre-script actions to be performed within the function below
      execute_pre_script() {
          echo "INFO: Start execution of pre-script"
      }

      # Add all post-script actions to be performed within the function below
      execute_post_script() {
          echo "INFO: Start execution of post-script"
      }

      # Debug logging for parameters passed to the SSM document
      echo "INFO: ${OPERATION} starting at $(date) with executionId: ${EXECUTION_ID}"

      # Based on the command parameter value execute the function that supports 
      # pre-script/post-script operation
      case ${OPERATION} in
          pre-script)
              execute_pre_script
              ;;
          post-script)
              execute_post_script
              ;;
          dry-run)
              echo "INFO: dry-run option invoked - taking no action"
              ;;
          *)
              echo "ERROR: Invalid command parameter passed. Please use either pre-script, post-script, dry-run."
              exit 1 # return failure
              ;;
      esac

      END=$(date +%s)
      # Debug Log for profiling the script time
      echo "INFO: ${OPERATION} completed at $(date). Total runtime: $((${END} - ${START})) seconds."
```

------

获得 SSM 文档内容后，请参照以下过程之一创建自定义 SSM 文档。

------
#### [ Console ]

**创建 SSM 命令文档**

1. 打开 AWS Systems Manager 控制台，网址为[https://console.aws.amazon.com//systems-manager/](https://console.aws.amazon.com//systems-manager/)。

1. 在导航窗格中，选择**文档**，然后选择**创建文档**、**命令或会话**。

1. 对于**名称**，为文档输入一个描述性名称。

1. 对于**目标类型**，选择**/AWS::EC2::Instance**。

1. 对于**文档类型**，请选择**命令**。

1. 在**内容**字段中，选择 **YAML**，然后粘贴文档内容。

1. 在**文档标签**部分，添加标签键为 `DLMScriptsAccess`、标签值为 `true` 的标签。
**重要**  
该`DLMScriptsAccess:true`标签是*步骤 3：准备 Amazon Data Lifecycle Manager IAM 角色*中使用的**AWSDataLifecycleManagerSSMFull访问** AWS 托管策略所必需的。该策略使用 `aws:ResourceTag` 条件键来限制对带有此标签的 SSM 文档的访问权限。

1. 选择**创建文档**。

------
#### [ AWS CLI ]

**创建 SSM 命令文档**  
使用 [create-document](https://docs.aws.amazon.com/cli/latest/reference/ssm/create-document.html) 命令。对于 `--name`，请为文档指定一个描述性名称。对于 `--document-type`，请指定 `Command`。对于 `--content`，请指定包含 SSM 文档内容的.yaml 文件的路径。对于 `--tags`，请指定 `"Key=DLMScriptsAccess,Value=true"`。

```
$ aws ssm create-document \
--content file://path/to/file/documentContent.yaml \
--name "document_name" \
--document-type "Command" \
--document-format YAML \
--tags "Key=DLMScriptsAccess,Value=true"
```

------

### 步骤 3：准备 Amazon Data Lifecycle Manager IAM 角色
<a name="prep-iam-role"></a>

**注意**  
如果出现以下情况，则需要执行此步骤：  
您可以创建或更新使用自定义 IAM 角色的 pre/post 支持脚本的快照策略。
您可以使用命令行创建或更新使用默认值的 pre/post 启用脚本的快照策略。
如果您使用控制台创建或更新使用默认角色管理快照的 pre/post 启用脚本的快照策略（**AWSDataLifecycleManagerDefaultRole**），请跳过此步骤。在这种情况下，我们会自动将**AWSDataLifecycleManagerSSMFull访问**策略附加到该角色。

您必须确保您用于策略的 IAM 角色授予 Amazon Data Lifecycle Manager 权限，以执行在策略作为目标的实例上运行前置和后置脚本所需的 SSM 操作。

Amazon Data Lifecycle Manager 提供了包含所需权限的托管策略（**AWSDataLifecycleManagerSSMFull访问**权限）。您可以将此策略附加到您的 IAM 角色以管理快照，从而确保其包含这些权限。

**重要**  
使用预脚本和后置脚本时， AWSDataLifecycleManagerSSMFull访问管理策略使用`aws:ResourceTag`条件键来限制对特定 SSM 文档的访问。要允许 Amazon Data Lifecycle Manager 访问 SSM 文档，您必须确保您的 SSM 文档带有 `DLMScriptsAccess:true` 标签。

或者，您可以手动创建自定义策略或将所需权限直接分配给您使用的 IAM 角色。您可以使用 AWSDataLifecycleManagerSSMFull访问管理策略中定义的相同权限，但是，`aws:ResourceTag`条件键是可选的。如果您决定不包含该条件键，则无需用 `DLMScriptsAccess:true` 标记您的 SSM 文档。

使用以下方法之一将**AWSDataLifecycleManagerSSMFull访问**策略添加到您的 IAM 角色。

------
#### [ Console ]

**将托管策略附加到您的自定义角色**

1. 使用 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

1. 在导航面板中，选择 **Roles**（角色）。

1. 搜索并选择用于管理快照的自定义角色。

1. 在**权限**选项卡上，选择**添加权限**、**附加策略**。

1. 搜索并选择**AWSDataLifecycleManagerSSMFull访问**托管策略，然后选择**添加权限**。

------
#### [ AWS CLI ]

**将托管策略附加到您的自定义角色**  
使用 [ attach-role-policy](https://docs.aws.amazon.com/cli/latest/reference/iam/attach-role-policy.html) 命令。对于 `---role-name`，请指定您自定义角色的名称。对于 `--policy-arn`，请指定 `arn:aws:iam::aws:policy/AWSDataLifecycleManagerSSMFullAccess`。

```
$ aws iam attach-role-policy \
--policy-arn arn:aws:iam::aws:policy/AWSDataLifecycleManagerSSMFullAccess \
--role-name your_role_name
```

------

### 步骤 4：创建快照生命周期策略
<a name="prep-policy"></a>

要自动生成应用程序一致性快照，您必须创建以实例为目标的快照生命周期策略，并为该策略配置前置和后置脚本。

------
#### [ Console ]

**创建快照生命周期策略**

1. 打开位于 [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/) 的 Amazon EC2 控制台。

1. 在导航窗格中，依次选择 **Elastic Block Store** 和**生命周期管理器**，然后选择**创建生命周期策略**。

1. 在**选择策略类型**页面上，选择 **EBS 快照策略**，然后选择**下一步**。

1. 在**目标资源**部分中，执行以下操作：

   1. 对于**目标资源类型**，请选择 `Instance`。

   1. 对于**目标资源标签**，请指定识别要备份的实例的资源标签。仅备份具有指定标签的资源。

1. 对于 **IAM 角色**，可以选择 **AWSDataLifecycleManagerDefaultRole**（用于管理快照的默认角色），也可以选择一个您创建并准备用于预处理和发布脚本的自定义角色。

1. 根据需要配置计划和其他选项。我们建议您将快照创建时间计划在与您工作负载相匹配的时间段，例如在维护窗口期间。

   对于 SAP HANA，我们建议您启用“快速快照还原”。
**注意**  
如果您为 VSS 备份启用计划，则无法启用**排除特定数据卷**或**从源中复制标签**。

1. 在**前置和后置脚本**部分中，选择**启用前置和后置脚本**，然后根据您的工作负载执行以下操作：
   + 要创建 Windows 应用程序的应用程序一致性快照，请选择 **VSS 备份**。
   + 要创建您的 SAP HANA 工作负载的应用程序一致性快照，请选择 **SAP HANA**。
   + **要使用自定义 SSM 文档为所有其他数据库和工作负载（包括自行管理的 MySQL、PostgreSQL InterSystems 或 IRIS 数据库）创建应用程序一致的快照，请选择自定义 SSM 文档。**

     1. 对于**自动化选项**，请选择**前置和后置脚本**。

     1. 对于 **SSM 文档**，请选择您准备的 SSM 文档。

1. 根据您所选的选项，配置以下其他选项：
   + **脚本超时** –（*仅限自定义 SSM 文档*）如果脚本运行尝试尚未完成，则在此超时期间后，Amazon Data Lifecycle Manager 的尝试失败。如果脚本未在其超时期间内完成，Amazon Data Lifecycle Manager 的尝试失败。超时期间分别适用于前置和后置脚本。最小的默认超时期间为 10 秒。最长超时期间为 120 秒。
   + **重试失败的脚本** – 选择此选项可重试未在其超时期间内完成的脚本。如果前置脚本失败，则 Amazon Data Lifecycle Manager 会重试整个快照创建过程，包括运行前置和后置脚本。如果后置脚本失败，则 Amazon Data Lifecycle Manager 将仅重试后置脚本；在这种情况下，前置脚本将完成并且可能已创建快照。
   + **默认创建崩溃一致性快照** – 如果前置脚本运行失败，则选择此选项以默认创建崩溃一致性快照。如果未启用前置和后置脚本，则这是 Amazon Data Lifecycle Manager 的默认快照创建行为。如果您启用了重试，则只有在所有重试尝试都用尽之后，Amazon Data Lifecycle Manager 才会默认创建崩溃一致性快照。如果前置脚本失败并且您没有默认创建崩溃一致性快照，则 Amazon Data Lifecycle Manager 将不会在该计划运行期间为实例创建快照。
**注意**  
如果您要为 SAP HANA 创建快照，则可能需要禁用此选项。无法以相同的方式还原 SAP HANA 工作负载的崩溃一致性快照。

1. 选择**创建默认策略**。
**注意**  
如果发生 `Role with name AWSDataLifecycleManagerDefaultRole already exists` 错误，请参阅 [排查 Amazon Data Lifecycle Manager 问题](dlm-troubleshooting.md) 来了解更多信息。

------
#### [ AWS CLI ]

**创建快照生命周期策略**  
使用[create-lifecycle-policy](https://docs.aws.amazon.com/cli/latest/reference/dlm/create-lifecycle-policy.html)命令，并将`Scripts`参数包含在中`CreateRule`。有关参数的更多信息，请参阅 [Amazon Data Lifecycle Manager API Reference](https://docs.aws.amazon.com/dlm/latest/APIReference/API_Script.html)**。

```
$ aws dlm create-lifecycle-policy \
--description "policy_description" \
--state ENABLED \
--execution-role-arn iam_role_arn \
--policy-details file://policyDetails.json
```

其中 `policyDetails.json` 包含以下内容之一，具体取决于您的用例：
+ **VSS 备份**

  ```
  {
      "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
      "ResourceTypes": [
          "INSTANCE"
      ],
      "TargetTags": [{
          "Key": "tag_key",
          "Value": "tag_value"
      }],
      "Schedules": [{
          "Name": "schedule_name",
          "CreateRule": {
              "CronExpression": "cron_for_creation_frequency", 
              "Scripts": [{ 
                  "ExecutionHandler":"AWS_VSS_BACKUP",
                  "ExecuteOperationOnScriptFailure":true|false,
                  "MaximumRetryCount":retries (0-3)
              }]
          },
          "RetainRule": {
              "Count": retention_count
          }
      }]
  }
  ```
+ **SAP HANA 备份**

  ```
  {
      "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
      "ResourceTypes": [
          "INSTANCE"
      ],
      "TargetTags": [{
          "Key": "tag_key",
          "Value": "tag_value"
      }],
      "Schedules": [{
          "Name": "schedule_name",
          "CreateRule": {
              "CronExpression": "cron_for_creation_frequency", 
              "Scripts": [{ 
                  "Stages": ["PRE","POST"],
                  "ExecutionHandlerService":"AWS_SYSTEMS_MANAGER",
                  "ExecutionHandler":"AWSSystemsManagerSAP-CreateDLMSnapshotForSAPHANA",
                  "ExecuteOperationOnScriptFailure":true|false,
                  "ExecutionTimeout":timeout_in_seconds (10-120), 
                  "MaximumRetryCount":retries (0-3)
              }]
          },
          "RetainRule": {
              "Count": retention_count
          }
      }]
  }
  ```
+ **自定义 SSM 文档**

  ```
  {
      "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
      "ResourceTypes": [
          "INSTANCE"
      ],
      "TargetTags": [{
          "Key": "tag_key",
          "Value": "tag_value"
      }],
      "Schedules": [{
          "Name": "schedule_name",
          "CreateRule": {
              "CronExpression": "cron_for_creation_frequency", 
              "Scripts": [{ 
                  "Stages": ["PRE","POST"],
                  "ExecutionHandlerService":"AWS_SYSTEMS_MANAGER",
                  "ExecutionHandler":"ssm_document_name|arn",
                  "ExecuteOperationOnScriptFailure":true|false,
                  "ExecutionTimeout":timeout_in_seconds (10-120), 
                  "MaximumRetryCount":retries (0-3)
              }]
          },
          "RetainRule": {
              "Count": retention_count
          }
      }]
  }
  ```

------

## 使用 Amazon Data Lifecycle Manager 进行 VSS 备份的注意事项
<a name="app-consistent-vss"></a>

借助 Amazon Data Lifecycle Manager，您可以备份和还原在 Amazon EC2 实例上运行的启用 VSS（卷影复制服务）的 Windows 应用程序。如果应用程序已在 Windows VSS 中注册了 VSS 写入器，则 Amazon Data Lifecycle Manager 会为该应用程序创建具有应用程序一致性的快照。

**注意**  
Amazon Data Lifecycle Manager 目前仅支持在 Amazon EC2 上运行的资源的应用程序一致性快照，特别适用于可以通过将现有实例替换为从备份创建的新实例来还原应用程序数据的备份场景。并非所有实例类型或应用程序都支持 VSS 备份。有关更多信息，请参阅《Amazon EC2 用户指南》**中的[应用程序一致性 Windows VSS 快照](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/application-consistent-snapshots.html)。

**不支持的实例类型**  
以下 Amazon EC2 实例类型不支持 VSS 备份。如果您的策略以这些实例类型之一为目标，则 Amazon Data Lifecycle Manager 可能仍会创建 VSS 备份，但快照可能不会使用所需的系统标签进行标记。没有这些标签，快照在创建后将无法由 Amazon Data Lifecycle Manager 进行管理。您可能需要手动删除这些快照。
+ T3：`t3.nano` \$1 `t3.micro`
+ T3a：`t3a.nano` \$1 `t3a.micro`
+ T2：`t2.nano` \$1 `t2.micro`

## 应用程序一致性快照的共同责任
<a name="shared-responsibility"></a>

**您必须确保：**
+ SSM 代理已安装并在您的目标实例上运行 up-to-date
+ Systems Manager 有权在目标实例上执行所需操作
+ Amazon Data Lifecycle Manager 有权执行在目标实例上运行前置和后置脚本所需的 Systems Manager 操作。
+ 对于自定义工作负载，例如自行管理的 MySQL、PostgreSQL InterSystems 或 IRIS 数据库，您使用的 SSM 文档包含用于冻结、刷新和解冻数据库配置的正确和必需的操作。 I/O 
+ 快照创建时间与您的工作负载计划保持一致。例如，请尝试在计划的维护窗口期内安排快照创建。

**Amazon Data Lifecycle Manager 应确保：**
+ 快照创建将在计划快照创建时间的 60 分钟内启动。
+ 在启动快照创建之前运行前置脚本。
+ 在前置脚本成功且快照创建已启动后运行前置脚本。只有在前置脚本成功的情况下，Amazon Data Lifecycle Manager 才会运行后置脚本。如果前置脚本失败，Amazon Data Lifecycle Manager 将不会运行后置脚本。
+ 快照在创建时会用相应的标签进行标记。
+ CloudWatch 当脚本启动时，以及脚本失败或成功时，都会发出指标和事件。

# Data Lifecycle Manager 前置和后置脚本的其他使用场景
<a name="script-other-use-cases"></a>

除了使用前置和后置脚本自动生成应用程序一致性快照外，您还可以同时或单独使用前置和后置脚本，以在创建快照之前或之后自动执行其他管理任务。例如：
+ 创建快照之前使用前置脚本来应用补丁。这可以帮助您在应用每周或每月定期软件更新后创建快照。
**注意**  
如果您选择仅运行前置脚本，则默认情况下会启用**默认创建崩溃一致性快照**。
+ 创建快照后使用后置脚本应用补丁。这可以帮助您在应用每周或每月定期软件更新之前创建快照。

## 其他用例入门
<a name="dlm-script-other"></a>

本节介绍在**应用程序一致性快照以外的用例**中使用 and/or 发布前脚本时需要执行的步骤。

### 步骤 1：准备目标实例
<a name="dlm-script-other-prep-instance"></a>

**为 and/or 发布前脚本准备目标实例**

1. 在目标实例上安装 SSM Agent（如果尚未安装）。如果目标实例上已安装 SSM Agent，请跳过此步骤。
   + （Linux 实例）[在适用于 Linux 的 EC2 实例上手动安装 SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/manually-install-ssm-agent-linux.html)
   + （Windows 实例）[在适用于 Windows 的 EC2 实例上手动安装 SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-windows.html)

1. 确保 SSM Agent 正在运行。有关更多信息，请参阅[正在检查 SSM Agent 状态并启动代理](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-status-and-restart.html)。

1. 为 Amazon EC2 实例设置 Systems Manager。有关更多信息，请参阅《AWS Systems Manager 用户指南》**中的[为 Amazon EC2 实例设置 Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-setting-up-ec2.html)。

### 步骤 2：准备 SSM 文档
<a name="dlm-script-other-prep-document"></a>

您必须创建一个 SSM 命令文档，其中包含带有要运行的命令的 and/or 发布前脚本。

您可以使用下面的 SSM 文档空白模板创建 SSM 文档，并在相应的文档部分中添加前置和后置脚本命令。

**注意以下几点：**  
您负责确保 SSM 文档为工作负载执行正确和必需的操作。
SSM 文档必须包含 `allowedValues` 的必填字段，包括 `pre-script`、`post-script` 和 `dry-run`。Amazon Data Lifecycle Manager 将根据这些部分的内容在您的实例上执行命令。如果您的 SSM 文档没有这些部分，则 Amazon Data Lifecycle Manager 会将其视为执行失败。

```
###===============================================================================###
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
###===============================================================================###
schemaVersion: '2.2'
description: SSM Document Template for Amazon Data Lifecycle Manager Pre/Post script feature
parameters:
  executionId:
    type: String
    default: None
    description: (Required) Specifies the unique identifier associated with a pre and/or post execution
    allowedPattern: ^(None|[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$
  command:
  # Data Lifecycle Manager will trigger the pre-script and post-script actions during policy execution. 
  # 'dry-run' option is intended for validating the document execution without triggering any commands
  # on the instance. The following allowedValues will allow Data Lifecycle Manager to successfully 
  # trigger pre and post script actions.
    type: String
    default: 'dry-run'
    description: (Required) Specifies whether pre-script and/or post-script should be executed.
    allowedValues:
    - pre-script
    - post-script
    - dry-run

mainSteps:
- action: aws:runShellScript
  description: Run Database freeze/thaw commands
  name: run_pre_post_scripts
  precondition:
    StringEquals:
    - platformType
    - Linux
  inputs:
    runCommand:
    - |
      #!/bin/bash

      ###===============================================================================###
      ### Error Codes
      ###===============================================================================###
      # The following Error codes will inform Data Lifecycle Manager of the type of error 
      # and help guide handling of the error. 
      # The Error code will also be emitted via AWS Eventbridge events in the 'cause' field.
      # 1 Pre-script failed during execution - 201
      # 2 Post-script failed during execution - 202
      # 3 Auto thaw occurred before post-script was initiated - 203
      # 4 Pre-script initiated while post-script was expected - 204
      # 5 Post-script initiated while pre-script was expected - 205
      # 6 Application not ready for pre or post-script initiation - 206

      ###===============================================================================###
      ### Global variables
      ###===============================================================================###
      START=$(date +%s)
      # For testing this script locally, replace the below with OPERATION=$1.
      OPERATION={{ command }}

      # Add all pre-script actions to be performed within the function below
      execute_pre_script() {
          echo "INFO: Start execution of pre-script"
      }

      # Add all post-script actions to be performed within the function below
      execute_post_script() {
          echo "INFO: Start execution of post-script"
      }

      # Debug logging for parameters passed to the SSM document
      echo "INFO: ${OPERATION} starting at $(date) with executionId: ${EXECUTION_ID}"

      # Based on the command parameter value execute the function that supports 
      # pre-script/post-script operation
      case ${OPERATION} in
          pre-script)
              execute_pre_script
              ;;
          post-script)
              execute_post_script
              ;;
          dry-run)
              echo "INFO: dry-run option invoked - taking no action"
              ;;
          *)
              echo "ERROR: Invalid command parameter passed. Please use either pre-script, post-script, dry-run."
              exit 1 # return failure
              ;;
      esac

      END=$(date +%s)
      # Debug Log for profiling the script time
      echo "INFO: ${OPERATION} completed at $(date). Total runtime: $((${END} - ${START})) seconds."
```

### 步骤 3：准备 Amazon Data Lifecycle Manager IAM 角色
<a name="dlm-script-other-prep-role"></a>

**注意**  
如果出现以下情况，则需要执行此步骤：  
您可以创建或更新使用自定义 IAM 角色的 pre/post 支持脚本的快照策略。
您可以使用命令行创建或更新使用默认值的 pre/post 启用脚本的快照策略。
如果您使用控制台创建或更新使用默认角色管理快照的 pre/post 启用脚本的快照策略（**AWSDataLifecycleManagerDefaultRole**），请跳过此步骤。在这种情况下，我们会自动将**AWSDataLifecycleManagerSSMFull访问**策略附加到该角色。

您必须确保用于策略的 IAM 角色授予 Amazon Data Lifecycle Manager 权限，以执行在策略作为目标的实例上运行前置和后置脚本所需的 SSM 操作的权限。

Amazon Data Lifecycle Manager 提供了包含所需权限的托管策略（**AWSDataLifecycleManagerSSMFull访问**权限）。您可以将此策略附加到您的 IAM 角色以管理快照，从而确保其包含这些权限。

**重要**  
使用预脚本和后置脚本时， AWSDataLifecycleManagerSSMFull访问管理策略使用`aws:ResourceTag`条件键来限制对特定 SSM 文档的访问。要允许 Amazon Data Lifecycle Manager 访问 SSM 文档，您必须确保您的 SSM 文档带有 `DLMScriptsAccess:true` 标签。

或者，您可以手动创建自定义策略或将所需权限直接分配给您使用的 IAM 角色。您可以使用 AWSDataLifecycleManagerSSMFull访问管理策略中定义的相同权限，但是，`aws:ResourceTag`条件键是可选的。如果您决定不使用该条件键，则无需使用 `DLMScriptsAccess:true` 标记您的 SSM 文档。

使用以下方法之一将**AWSDataLifecycleManagerSSMFull访问**策略添加到您的 IAM 角色。

------
#### [ Console ]

**将托管策略附加到您的自定义角色**

1. 使用 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

1. 在导航面板中，选择 **Roles**（角色）。

1. 搜索并选择用于管理快照的自定义角色。

1. 在**权限**选项卡上，选择**添加权限**、**附加策略**。

1. 搜索并选择**AWSDataLifecycleManagerSSMFull访问**托管策略，然后选择**添加权限**。

------
#### [ AWS CLI ]

**将托管策略附加到您的自定义角色**  
使用 [ attach-role-policy](https://docs.aws.amazon.com/cli/latest/reference/iam/attach-role-policy.html) 命令。对于 `---role-name`，请指定您自定义角色的名称。对于 `--policy-arn`，请指定 `arn:aws:iam::aws:policy/AWSDataLifecycleManagerSSMFullAccess`。

```
$ aws iam attach-role-policy \
--policy-arn arn:aws:iam::aws:policy/AWSDataLifecycleManagerSSMFullAccess \
--role-name your_role_name
```

------

### 创建快照生命周期策略
<a name="dlm-script-other-prep-policy"></a>

------
#### [ Console ]

**创建快照生命周期策略**

1. 打开位于 [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/) 的 Amazon EC2 控制台。

1. 在导航窗格中，依次选择 **Elastic Block Store** 和**生命周期管理器**，然后选择**创建生命周期策略**。

1. 在**选择策略类型**页面上，选择 **EBS 快照策略**，然后选择**下一步**。

1. 在**目标资源**部分中，执行以下操作：

   1. 对于**目标资源类型**，请选择 `Instance`。

   1. 对于**目标资源标签**，请指定识别要备份的实例的资源标签。仅备份具有指定标签的资源。

1. 对于 **IAM 角色**，可以选择 **AWSDataLifecycleManagerDefaultRole**（用于管理快照的默认角色），也可以选择一个您创建并准备用于预处理和发布脚本的自定义角色。

1. 根据需要配置计划和其他选项。我们建议您将快照创建时间计划在与您工作负载相匹配的时间段，例如在维护窗口期间。

1. 在**前置和后置脚本**部分中，选择**启用前置和后置脚本**，然后执行以下操作：

   1. 选择**自定义 SSM 文档**。

   1. 对于**自动化选项**，请选择与要运行的脚本相匹配的选项。

   1. 对于 **SSM 文档**，请选择您准备的 SSM 文档。

1. 如果需要，请配置以下其他选项：
   + **脚本超时** – 如果脚本运行尝试尚未完成，则在此超时期间后，Amazon Data Lifecycle Manager 的尝试失败。如果脚本未在其超时期间内完成，Amazon Data Lifecycle Manager 的尝试失败。超时期间分别适用于前置和后置脚本。最小的默认超时期间为 10 秒。最长超时期间为 120 秒。
   + **重试失败的脚本** – 选择此选项可重试未在其超时期间内完成的脚本。如果前置脚本失败，则 Amazon Data Lifecycle Manager 会重试整个快照创建过程，包括运行前置和后置脚本。如果后置脚本失败，则 Amazon Data Lifecycle Manager 将仅重试后置脚本；在这种情况下，前置脚本将完成并且可能已创建快照。
   + **默认创建崩溃一致性快照** – 如果前置脚本运行失败，则选择此选项以默认创建崩溃一致性快照。如果未启用前置和后置脚本，则这是 Amazon Data Lifecycle Manager 的默认快照创建行为。如果您启用了重试，则只有在所有重试尝试都用尽之后，Amazon Data Lifecycle Manager 才会默认创建崩溃一致性快照。如果前置脚本失败并且您没有默认创建崩溃一致性快照，则 Amazon Data Lifecycle Manager 将不会在该计划运行期间为实例创建快照。

1. 选择**创建默认策略**。
**注意**  
如果发生 `Role with name AWSDataLifecycleManagerDefaultRole already exists` 错误，请参阅 [排查 Amazon Data Lifecycle Manager 问题](dlm-troubleshooting.md) 来了解更多信息。

------
#### [ AWS CLI ]

**创建快照生命周期策略**  
使用[create-lifecycle-policy](https://docs.aws.amazon.com/cli/latest/reference/dlm/create-lifecycle-policy.html)命令，并将`Scripts`参数包含在中`CreateRule`。有关参数的更多信息，请参阅 [Amazon Data Lifecycle Manager API Reference](https://docs.aws.amazon.com/dlm/latest/APIReference/API_Script.html)**。

```
$ aws dlm create-lifecycle-policy \
--description "policy_description" \
--state ENABLED \
--execution-role-arn iam_role_arn \
--policy-details file://policyDetails.json
```

其中 `policyDetails.json` 包含以下内容。

```
{
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "ResourceTypes": [
        "INSTANCE"
    ],
    "TargetTags": [{
        "Key": "tag_key",
        "Value": "tag_value"
    }],
    "Schedules": [{
        "Name": "schedule_name",
        "CreateRule": {
            "CronExpression": "cron_for_creation_frequency", 
            "Scripts": [{ 
                "Stages": ["PRE" | "POST" | "PRE","POST"],
                "ExecutionHandlerService":"AWS_SYSTEMS_MANAGER",
                "ExecutionHandler":"ssm_document_name|arn",
                "ExecuteOperationOnScriptFailure":true|false,
                "ExecutionTimeout":timeout_in_seconds (10-120), 
                "MaximumRetryCount":retries (0-3)
            }]
        },
        "RetainRule": {
            "Count": retention_count
        }
    }]
}
```

------

# Amazon Data Lifecycle Manager 前置和后置脚本的工作原理
<a name="script-flow"></a>

下图显示了使用自定义 SSM 文档时前置和后置脚本的流程。这不适用于 VSS 备份。

![\[Amazon Data Lifecycle Manager 前置和后置脚本流程\]](http://docs.aws.amazon.com/zh_cn/ebs/latest/userguide/images/dlm-scripts.png)


在计划创建快照时，会发生以下操作和跨服务交互。

1. Amazon Data Lifecycle Manager 通过调用 SSM 文档并传递 `pre-script` 参数来启动前置脚本操作。
**注意**  
只有在运行前置脚本时才会执行步骤 1 到 3。如果您仅运行后置脚本，则会跳过步骤 1 到 3。

1. Systems Manager 向在目标实例上运行的 SSM Agent 发送前置脚本命令。SSM Agent 在实例上运行命令，并将状态信息发送回 Systems Manager。

   例如，如果使用 SSM 文档创建应用程序一致的快照，则预脚本可能会冻结并刷新， I/O 以确保在拍摄快照之前将所有缓冲的数据写入卷。

1. Systems Manager 向 Amazon Data Lifecycle Manager 发送前置脚本命令状态更新。如果前置脚本失败，则 Amazon Data Lifecycle Manager 将执行以下操作之一，具体取决于您配置前置和后置脚本选项的方式：    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ebs/latest/userguide/script-flow.html)

1. Amazon Data Lifecycle Manager 启动快照创建。

1. Amazon Data Lifecycle Manager 通过调用 SSM 文档并传递 `post-script` 参数来启动后置脚本操作。
**注意**  
只有在运行前置脚本时才会执行步骤 5 到 7。如果您仅运行后置脚本，则会跳过步骤 1 到 3。

1. Systems Manager 向在目标实例上运行的 SSM Agent 发送后置脚本命令。SSM Agent 在实例上运行命令，并将状态信息发送回 Systems Manager。

   例如，如果 SSM 文档启用了应用程序一致性快照，则此发布脚本可能会解冻， I/O 以确保您的数据库在拍摄快照后恢复正常 I/O 操作。

1. 如果您运行后置脚本且 Systems Manager 指示该脚本已成功完成，则该过程完成。

   如果后置脚本失败，则 Amazon Data Lifecycle Manager 将执行以下操作之一，具体取决于您配置前置和后置脚本选项的方式：    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ebs/latest/userguide/script-flow.html)

   请记住，如果后置脚本失败，则前置脚本（如已启用）将成功完成，并且可能已创建快照。您可能需要对实例采取进一步操作以确保其按预期运行。例如，如果预脚本暂停并刷新I/O, but the post script failed to thaw I/O, you might need to configure your database to auto-thaw I/O or you need to manually thaw I/O。

1. 后置脚本完成后，快照创建过程可能会完成。完成快照所需的时间取决于快照的大小。

# 识别使用 Data Lifecycle Manager 前置和后置脚本创建的快照
<a name="dlm-script-tags"></a>

Amazon Data Lifecycle Manager 会自动为使用前置和后置脚本创建的快照分配以下系统标签。
+ 密钥：`aws:dlm:pre-script`；值：`SUCCESS`\$1`FAILED`

  标签值为 `SUCCESS` 表示前置脚本已成功执行。标签值为 `FAILED` 表示前置脚本未成功执行。
+ 密钥：`aws:dlm:post-script`；值：`SUCCESS`\$1`FAILED`

  标签值为 `SUCCESS` 表示后置脚本已成功执行。标签值为 `FAILED` 表示后置脚本未成功执行。

对于自定义 SSM 文档和 SAP HANA 备份，如果快照同时用 `aws:dlm:pre-script:SUCCESS` 和 `aws:dlm:post-script:SUCCESS` 标记，则可以推断成功创建了应用程序一致性快照。

此外，使用 VSS 备份创建的应用程序一致性快照会自动标记：
+ 密钥：`AppConsistent tag`；值：`true`\$1`false`

  标签值为 `true` 表示 VSS 备份成功且快照具有应用程序一致性。标签值为 `false` 表示 VSS 备份未成功，并且快照不符合应用程序一致性。

# 监控 Amazon Data Lifecycle Manager 前置和后置脚本
<a name="dlm-script-monitoring"></a>

**亚马逊 CloudWatch 指标**  
Amazon Data Lifecycle Manager 会在脚本前后失败和成功以及 VSS 备份失败和成功时发布以下 CloudWatch 指标。
+ `PreScriptStarted`
+ `PreScriptCompleted`
+ `PreScriptFailed`
+ `PostScriptStarted`
+ `PostScriptCompleted`
+ `PostScriptFailed`
+ `VSSBackupStarted`
+ `VSSBackupCompleted`
+ `VSSBackupFailed`

有关更多信息，请参阅 [使用监控数据生命周期管理器策略 CloudWatch](monitor-dlm-cw-metrics.md)。

**Amazon EventBridge**  
当前脚本或后脚本启动、成功或失败时，Amazon Data Lifecycle Manager 会发出以下亚马逊 EventBridge 事件
+ `DLM Pre Post Script Notification`

有关更多信息，请参阅 [使用监控数据生命周期管理器策略 EventBridge](monitor-cloudwatch-events.md)。