

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

# 使用 AWSTOE 组件文档框架创建自定义组件
<a name="toe-use-documents"></a>

要使用 AWS Task Orchestrator and Executor (AWSTOE) 组件框架构建组件，必须提供一个基于 YAML 的文档，该文档表示适用于您创建的组件的阶段和步骤。 AWS 服务 当他们创建新的 Amazon 系统映像 (AMI) 或容器映像时，请使用您的组件。

**Topics**
+ [组件文档工作流程](#component-doc-workflow)
+ [组件日志](#component-logging)
+ [输入和输出链](#document-chaining)
+ [文档架构和定义](#document-schema)
+ [文档示例](#document-example)
+ [在自定义组件文档中使用变量](toe-user-defined-variables.md)
+ [在中使用条件构造 AWSTOE](toe-conditional-constructs.md)
+ [在 AWSTOE 组件文档中使用比较运算符](toe-comparison-operators.md)
+ [在 AWSTOE 组件文档中使用逻辑运算符](toe-logical-operators.md)
+ [在中使用循环结构 AWSTOE](toe-looping-constructs.md)

## 组件文档工作流程
<a name="component-doc-workflow"></a>

 AWSTOE 组件文档使用阶段和步骤对相关任务进行分组，并将这些任务组织成组件的逻辑工作流程。

**提示**  
使用您的组件构建映像的服务可能会实施有关构建过程使用哪些阶段，以及何时允许这些阶段运行的规则。您在设计组件时，请务必考虑这一点。

**阶段**  
阶段表示您的工作流程在映像构建过程中的进展。例如，Image Builder 服务在其*构建阶段*对其生成的映像使用 `build` 和 `validate` 阶段。它在*测试阶段*使用 `test` 和 `container-host-test` 阶段来确保在创建最终 AMI 或分发容器映像之前，映像快照或容器映像产生预期的结果。

当组件运行时，每个阶段的关联命令将按照它们在组件文档中出现的顺序进行应用。

**阶段规则**
+ 每个阶段名称在文档中必须是唯一的。
+ 您可以在文档中定义多个阶段。
+ 您必须在文档中至少包含以下至少一个阶段：
  + **构建** — 对于 Image Builder，此阶段通常在*构建阶段*使用。
  + **验证** — 对于 Image Builder，此阶段通常在*构建阶段*使用。
  + **测试** — 对于 Image Builder，此阶段通常在*测试阶段*使用。
+ 阶段始终按照文档中定义的顺序运行。中为 AWSTOE 命令指定它们的顺序 AWS CLI 无效。

**Steps**  
步骤是定义每个阶段中的工作流程的各个工作单元。步骤按先后顺序运行。但是，一个步骤的输入或输出也可以作为输入馈送到后续步骤中。这就是所谓的“链”。

**步骤规则**
+ 步骤名称对于阶段来说必须是唯一的。
+ 步骤必须使用可返回退出代码的支持的操作（操作模块）。

  有关支持的操作模块、其工作原理、 input/output 值和示例的完整列表，请参阅[AWSTOE 组件管理器支持的操作模块](toe-action-modules.md)。

## 组件日志
<a name="component-logging"></a>

AWSTOE 每次运行组件时，都会在 EC2 实例上创建一个新的日志文件夹，用于构建和测试新映像。对于容器映像，日志文件夹存储在容器中。

为了帮助在图像创建过程中出现问题时进行故障排除，在运行组件时 AWSTOE 创建的输入文档和所有输出文件都存储在日志文件夹中。

日志文件夹名称由以下部分组成：

1. **日志目录** — 当服务运行 AWSTOE 组件时，它会与该命令的其他设置一起传入日志目录。在以下示例中，我们展示了 Image Builder 使用的日志文件格式。
   + **Linux 和 macOS**：`/var/lib/amazon/toe/`
   + **Windows**：`$env:ProgramFiles\Amazon\TaskOrchestratorAndExecutor\`

1. **文件前缀** — 这是用于所有组件的标准前缀：“`TOE_`”。

1. **运行时间** — 这是一个 YYYY-MM-DD \$1HH-MM-SS\$1UTC-0 格式的时间戳。

1. **执行 ID**-这是 AWSTOE 运行一个或多个组件时分配的 GUID。

示例：`/var/lib/amazon/toe/TOE_2021-07-01_12-34-56_UTC-0_a1bcd2e3-45f6-789a-bcde-0fa1b2c3def4`

AWSTOE 将以下核心文件存储在日志文件夹中：

**输入文件**
+ **document.yaml** — 用作命令输入的文档。组件运行后，该文件将作为构件存储。

**输出文件**
+ **application.log** — 应用程序日志包含来自 AWSTOE 、带有时间戳的调试级别信息，这些信息有关组件运行时发生的情况。
+ **detailedoutput.json** — 此 JSON 文件包含有关组件运行时适用于组件的所有文档、阶段和步骤的运行状态、输入、输出和失败的详细信息。
+ **console.log** — 控制台日志包含组件运行时 AWSTOE 写入控制台的所有标准输出 (stdout) 和标准错误 (stderr) 信息。
+ **chaining.json** — 此 JSON 文件表示 AWSTOE 应用于解析链接表达式的优化。

**注意**  
日志文件夹还可能包含此处未涵盖的其他临时文件。

## 输入和输出链
<a name="document-chaining"></a>

 AWSTOE 配置管理应用程序提供了一种通过编写以下格式的参考文献来链接输入和输出的功能：

`{{ phase_name.step_name.inputs/outputs.variable }}`

或者

`{{ phase_name.step_name.inputs/outputs[index].variable }}`

通过使用链功能，您可以回收代码并提高文档的可维护性。

**链式规则**
+ 只能在每个步骤的输入部分中使用链表达式。
+ 具有链表达式的语句必须用引号引起来。例如：
  + **无效的表达式**：`echo {{ phase.step.inputs.variable }}`
  + **有效的表达式**：`"echo {{ phase.step.inputs.variable }}"`
  + **有效的表达式**：`'echo {{ phase.step.inputs.variable }}'`
+ 链表达式可以引用同一文档中的其他步骤和阶段的变量。但是，调用服务可能有一些规则，要求链表达式只能在单个阶段的上下文中运行。例如，Image Builder 不支持从*构建阶段*到*测试阶段*的链接，因为它独立运行每个阶段。
+ 链表达式中的索引从零开始。索引以零 (0) 开头，以引用第一个元素。

**示例**

要在以下示例步骤的第二个条目中引用源变量，链模式为 `{{ build.SampleS3Download.inputs[1].source }}`。

```
phases:
  - name: 'build'
    steps:
      - name: SampleS3Download
        action: S3Download
        timeoutSeconds: 60
        onFailure: Abort
        maxAttempts: 3
        inputs:
          - source: 's3://sample-bucket/sample1.ps1'
            destination: 'C:\sample1.ps1'
          - source: 's3://sample-bucket/sample2.ps1'
            destination: 'C:\sample2.ps1'
```

要引用以下示例步骤的输出变量（等于“Hello”），链模式为 `{{ build.SamplePowerShellStep.outputs.stdout }}`。

```
phases:
  - name: 'build'
    steps:
      - name: SamplePowerShellStep
        action: ExecutePowerShell
        timeoutSeconds: 120
        onFailure: Abort
        maxAttempts: 3
        inputs:
          commands:
            - 'Write-Host "Hello"'
```

## 文档架构和定义
<a name="document-schema"></a>

以下是文档的 YAML 架构。

```
name: (optional)
description: (optional)
schemaVersion: "string"

phases:
  - name: "string"
    steps:
      - name: "string"
        action: "string"
        timeoutSeconds: integer
        onFailure: "Abort|Continue|Ignore"
        maxAttempts: integer
        inputs:
```

文档的架构定义如下所示。


| 字段 | 描述 | Type | 必需 | 
| --- | --- | --- | --- | 
| name | 文档的名称。 | 字符串 | 否 | 
| 描述 | 文档的描述。 | 字符串 |  否  | 
| schemaVersion | 文档的架构版本，当前为 1.0。 | 字符串 |  是  | 
| phases | 阶段及其步骤的列表。 |  列表  |  是  | 

阶段的架构定义如下所示。


| 字段 | 描述 | Type | 必需 | 
| --- | --- | --- | --- | 
| name | 阶段的名称。 | 字符串 | 是 | 
| 步骤 | 阶段中的步骤列表。 | 列表  |  是  | 

步骤的架构定义如下所示。


| 字段 | 描述 | Type | 必需 | 默认 值 | 
| --- | --- | --- | --- | --- | 
| name | 用户定义的步骤名称。 | 字符串 |  |  | 
| action | 与运行步骤的模块相关的关键字。 | 字符串 |  |  | 
| timeoutSeconds |  在失败或重试之前，步骤运行的秒数。 此外，支持 -1 值，表示无限超时。不允许 0 和其他负值。  | 整数 |  否  | 7,200 秒（120 分钟） | 
| onFailure |  指定该步骤在失败时应执行的操作。有效值如下所示： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/imagebuilder/latest/userguide/toe-use-documents.html)  |  字符串  |  否  |  中止 | 
| maxAttempts | 在步骤失败之前允许的最大尝试次数。 | 整数 |  否  | 1 | 
| inputs | 包含操作模块运行步骤所需的参数。 | 字典 |  是  |  | 

## 文档示例
<a name="document-example"></a>

以下示例显示了为目标操作系统执行任务的 AWSTOE 组件文档。

------
#### [ Linux ]

**示例 1：运行自定义二进制文件**  
以下是在 Linux 实例上下载和运行自定义二进制文件的示例文档。

```
name: LinuxBin
description: Download and run a custom Linux binary file.
schemaVersion: 1.0
phases:
  - name: build
    steps:
      - name: Download
        action: S3Download
        inputs:
          - source: s3://<replaceable>amzn-s3-demo-source-bucket</replaceable>/<replaceable>myapplication</replaceable>
            destination: /tmp/<replaceable>myapplication</replaceable>
      - name: Enable
        action: ExecuteBash
        onFailure: Continue
        inputs:
          commands:
            - 'chmod u+x {{ build.Download.inputs[0].destination }}'
      - name: Install
        action: ExecuteBinary
        onFailure: Continue
        inputs:
          path: '{{ build.Download.inputs[0].destination }}'
          arguments:
            - '--install'
      - name: Delete
        action: DeleteFile
        inputs:
          - path: '{{ build.Download.inputs[0].destination }}'
```

------
#### [ Windows ]

**示例 1：安装 Windows 更新**  
以下是一个示例文档，用于安装所有可用的 Windows 更新，运行配置脚本，在创建 AMI 之前验证更改以及在创建 AMI 后测试更改。

```
name: RunConfig_UpdateWindows
description: 'This document will install all available Windows updates and run a config script. It will then validate the changes before an AMI is created. Then after AMI creation, it will test all the changes.'
schemaVersion: 1.0
phases:
  - name: build
    steps:
      - name: DownloadConfigScript
        action: S3Download
        timeoutSeconds: 60
        onFailure: Abort
        maxAttempts: 3
        inputs:
          - source: 's3://customer-bucket/config.ps1'
            destination: 'C:\config.ps1'

      - name: RunConfigScript
        action: ExecutePowerShell
        timeoutSeconds: 120
        onFailure: Abort
        maxAttempts: 3
        inputs:
          file: '{{build.DownloadConfigScript.inputs[0].destination}}'

      - name: Cleanup
        action: DeleteFile
        onFailure: Abort
        maxAttempts: 3
        inputs:
          - path: '{{build.DownloadConfigScript.inputs[0].destination}}'

      - name: RebootAfterConfigApplied
        action: Reboot
        inputs:
          delaySeconds: 60

      - name: InstallWindowsUpdates
        action: UpdateOS

  - name: validate
    steps:
      - name: DownloadTestConfigScript
        action: S3Download
        timeoutSeconds: 60
        onFailure: Abort
        maxAttempts: 3
        inputs:
          - source: 's3://customer-bucket/testConfig.ps1'
            destination: 'C:\testConfig.ps1'

      - name: ValidateConfigScript
        action: ExecutePowerShell
        timeoutSeconds: 120
        onFailure: Abort
        maxAttempts: 3
        inputs:
          file: '{{validate.DownloadTestConfigScript.inputs[0].destination}}'

      - name: Cleanup
        action: DeleteFile
        onFailure: Abort
        maxAttempts: 3
        inputs:
          - path: '{{validate.DownloadTestConfigScript.inputs[0].destination}}'

  - name: test
    steps:
      - name: DownloadTestConfigScript
        action: S3Download
        timeoutSeconds: 60
        onFailure: Abort
        maxAttempts: 3
        inputs:
          - source: 's3://customer-bucket/testConfig.ps1'
            destination: 'C:\testConfig.ps1'

      - name: ValidateConfigScript
        action: ExecutePowerShell
        timeoutSeconds: 120
        onFailure: Abort
        maxAttempts: 3
        inputs:
          file: '{{test.DownloadTestConfigScript.inputs[0].destination}}'
```

**示例 2：在 Windows 实例 AWS CLI 上安装**  
以下是使用安装文件在 Windows 实例 AWS CLI 上安装的示例文档。

```
name: InstallCLISetUp
description: Install &CLI; using the setup file
schemaVersion: 1.0
phases:
  - name: build
    steps:
      - name: Download
        action: S3Download
        inputs:
          - source: s3://aws-cli/AWSCLISetup.exe
            destination: C:\Windows\temp\AWSCLISetup.exe
      - name: Install
        action: ExecuteBinary
        onFailure: Continue
        inputs:
          path: '{{ build.Download.inputs[0].destination }}'
          arguments:
            - '/install'
            - '/quiet'
            - '/norestart'
      - name: Delete
        action: DeleteFile
        inputs:
          - path: '{{ build.Download.inputs[0].destination }}'
```

**示例 3：使用 MSI 安装程序安装 AWS CLI**  
以下是使用 MSI 安装程序安装 AWS CLI 的示例文档。

```
name: InstallCLIMSI
description: Install &CLI; using the MSI installer
schemaVersion: 1.0
phases:
  - name: build
    steps:
      - name: Download
        action: S3Download
        inputs:
          - source: s3://aws-cli/AWSCLI64PY3.msi
            destination: C:\Windows\temp\AWSCLI64PY3.msi
      - name: Install
        action: ExecuteBinary
        onFailure: Continue
        inputs:
          path: 'C:\Windows\System32\msiexec.exe'
          arguments:
            - '/i'
            - '{{ build.Download.inputs[0].destination }}'
            - '/quiet'
            - '/norestart'
      - name: Delete
        action: DeleteFile
        inputs:
          - path: '{{ build.Download.inputs[0].destination }}'
```

------
#### [ macOS ]

**示例 1：运行自定义 macOS 二进制文件**  
以下是在 macOS 实例上下载和运行自定义二进制文件的示例文档。

```
name: macOSBin
description: Download and run a binary file on macOS.
schemaVersion: 1.0
phases:
  - name: build
    steps:
      - name: Download
        action: S3Download
        inputs:
          - source: s3://<replaceable>amzn-s3-demo-source-bucket</replaceable>/<replaceable>myapplication</replaceable>
            destination: /tmp/<replaceable>myapplication</replaceable>
      - name: Enable
        action: ExecuteBash
        onFailure: Continue
        inputs:
          commands:
            - 'chmod u+x {{ build.Download.inputs[0].destination }}'
      - name: Install
        action: ExecuteBinary
        onFailure: Continue
        inputs:
          path: '{{ build.Download.inputs[0].destination }}'
          arguments:
            - '--install'
      - name: Delete
        action: DeleteFile
        inputs:
          - path: '{{ build.Download.inputs[0].destination }}'
```

------

# 在自定义组件文档中使用变量
<a name="toe-user-defined-variables"></a>

变量提供了一种以在整个应用程序中可使用的有意义的名称来标记数据的方法。您可以为复杂的工作流程定义格式简单易读的自定义变量，并在组件的 YAML 应用程序组件文档中引用它们。 AWSTOE 

本节提供的信息可帮助您在 YAML 应用程序 AWSTOE 组件文档中为组件定义变量，包括语法、名称约束和示例。

## 常量
<a name="user-defined-vars-constants"></a>

常量是不可变的变量，一旦定义就无法修改或覆盖。常量可以使用 AWSTOE 文档`constants`部分中的值来定义。

**常量名称规则**
+ 名称长度必须介于 3 到 128 个字符之间。
+ 该名称只能包含字母/数字字符（a-z、A-Z、0-9）、短划线 (-) 或下划线 (\$1)。
+ 在文档内，此名称必须是唯一的。
+ 必须将名称指定为 YAML 字符串。

**语法**

```
constants:
  - <name>:
      type: <constant type>
      value: <constant value>
```


| 键名称 | 必需 | 描述 | 
| --- | --- | --- | 
|  `name`  |  是  | 常量的名称。文档必须是唯一的（不得与任何其他参数名称或常量相同）。 | 
| `value` | 是 | 常量的值。 | 
| `type` | 是 | 常量的类型。支持的类型为 string。 | 

**在文档中引用常量值**  
您可以在 YAML 文档内的步骤或循环输入中引用常量，如下所示：
+ 常量引用区分大小写，并且名称必须完全匹配。
+ 名称必须用双大括号括`{{`*MyConstant*`}}`起来。
+ 允许在花括号内留出空格，并且会自动修剪空格。例如，以下所有引用均有效：

  `{{ MyConstant }}`, `{{ MyConstant}}`, `{{MyConstant }}`, `{{MyConstant}}`
+ YAML 文档中的引用必须指定为字符串（用单引号或双引号括起来）。

  例如：`- {{ MyConstant }}` 无效，因为它未被标识为字符串。

  但是，以下引用均有效：`- '{{ MyConstant }}'` 和 `- "{{ MyConstant }}"`。

**示例**  
步骤输入中引用的常量

```
name: Download AWS CLI version 2
schemaVersion: 1.0
constants:
  - Source:
      type: string
      value: https://awscli.amazonaws.com/AWSCLIV2.msi
phases:
  - name: build
    steps:
      - name: Download
        action: WebDownload
        inputs:
          - source: '{{ Source }}'
            destination: 'C:\Windows\Temp\AWSCLIV2.msi'
```

循环输入中引用的常量

```
name: PingHosts
schemaVersion: 1.0
constants:
  - Hosts:
      type: string
      value: 127.0.0.1,amazon.com
phases:
  - name: build
    steps:
      - name: Ping
        action: ExecuteBash
        loop:
          forEach:
            list: '{{ Hosts }}'
            delimiter: ','
        inputs:
          commands:
            - ping -c 4 {{ loop.value }}
```

## 参数
<a name="user-defined-vars-parameters"></a>

参数是可变变量，其设置由调用应用程序在运行时提供。您可以在 YAML 文档的 `Parameters` 部分中定义参数。

**参数名称规则**
+ 名称长度必须介于 3 到 128 个字符之间。
+ 该名称只能包含字母/数字字符（a-z、A-Z、0-9）、短划线 (-) 或下划线 (\$1)。
+ 在文档内，此名称必须是唯一的。
+ 必须将名称指定为 YAML 字符串。

### 语法
<a name="vars-parameters-syntax"></a>

```
parameters:
  - <name>:
      type: <parameter type>
      default: <parameter value>
      description: <parameter description>
```


| 键名称 | 必需 | 描述 | 
| --- | --- | --- | 
| `name` | 是 | 参数的名称。文档必须是唯一的（不得与任何其他参数名称或常量相同）。 | 
| `type` | 是 | 参数的数据类型。支持的类型包括：`string`。 | 
| `default` | 否 | 参数的默认值。 | 
| `description` | 否 | 描述参数。 | 

### 在文档中引用参数值
<a name="vars-parameters-referencing"></a>

您可以在 YAML 文档里的步骤或循环输入中引用参数，如下所示：
+ 参数引用区分大小写，并且名称必须完全匹配。
+ 名称必须用双大括号括`{{`*MyParameter*`}}`起来。
+ 允许在花括号内留出空格，并且会自动修剪空格。例如，以下所有引用均有效：

  `{{ MyParameter }}`, `{{ MyParameter}}`, `{{MyParameter }}`, `{{MyParameter}}`
+ YAML 文档中的引用必须指定为字符串（用单引号或双引号括起来）。

  例如：`- {{ MyParameter }}` 无效，因为它未被标识为字符串。

  但是，以下引用均有效：`- '{{ MyParameter }}'` 和 `- "{{ MyParameter }}"`。

**示例**  
以下示例显示如何在 YAML 文档中使用参数：
+ 参考步骤输入中的参数：

  ```
  name: Download AWS CLI version 2
  schemaVersion: 1.0
  parameters:
    - Source:
        type: string
        default: 'https://awscli.amazonaws.com/AWSCLIV2.msi'
        description: The AWS CLI installer source URL.
  phases:
    - name: build
      steps:
        - name: Download
          action: WebDownload
          inputs:
            - source: '{{ Source }}'
              destination: 'C:\Windows\Temp\AWSCLIV2.msi'
  ```
+ 参考循环输入中的参数：

  ```
  name: PingHosts
  schemaVersion: 1.0
  parameters:
    - Hosts:
        type: string
        default: 127.0.0.1,amazon.com
        description: A comma separated list of hosts to ping.
  phases:
    - name: build
      steps:
        - name: Ping
          action: ExecuteBash
          loop:
            forEach:
              list: '{{ Hosts }}'
              delimiter: ','
          inputs:
            commands:
              - ping -c 4 {{ loop.value }}
  ```

### 在运行时覆盖参数
<a name="vars-parameters-set-at-runtime"></a>

您可以将中的`--parameters`选项与键值对 AWS CLI 一起使用，在运行时设置参数值。
+ 将参数键值对指定为名称和值，用等号 (=) 分隔 (<name>=<value>)。
+ 多个参数必须用逗号分隔。
+ 在 YAML 组件文档中找不到的参数名称将被忽略。
+ 参数名称和值都是必需的。

**重要**  
组件参数是纯文本值，并且已记录在 AWS CloudTrail中。我们建议您使用 AWS Secrets Manager 或 P AWS Systems Manager arameter Store 来存储您的密钥。有关 Secrets Manager 的更多信息，请参阅*AWS Secrets Manager 用户指南*中的[什么是 Secrets Manager?](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)。有关 AWS Systems Manager Parameter Store 的更多信息，请参阅 *AWS Systems Manager 用户指南*中的 [AWS Systems Manager Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html)。

#### 语法
<a name="vars-runtime-parameters-syntax"></a>

```
--parameters name1=value1,name2=value2...
```


| CLI 选项 | 必需 | 说明 | 
| --- | --- | --- | 
| --参数 *name* =*value*，... | 否 | 此选项采用键/值对列表，以参数名称为键。 | 

**示例**  
以下示例显示如何在 YAML 文档中使用参数：
+ 此 `--parameter` 选项中指定的参数键值对无效：

  ```
  --parameters ntp-server=
  ```
+ 使用 AWS CLI中的 `--parameter` 选项设置一个参数键值对：

  ```
  --parameters ntp-server=ntp-server-windows-qe.us-east1.amazon.com
  ```
+ 使用 AWS CLI中的 `--parameter` 选项设置多个参数键值对：

  ```
  --parameters ntp-server=ntp-server.amazon.com,http-url=https://internal-us-east1.amazon.com
  ```

## 使用 Systems Manager 参数存储参数
<a name="toe-ssm-parameters"></a>

您可以通过在变量前面加上前缀来引用组件文档中的 AWS Systems Manager 参数存储参数（SSM 参数）。`aws:ssm`例如，

`{{ aws:ssm:/my/param }}`解析为 SSM 参数的值。`/my/param`

此功能支持以下 SSM 参数类型：
+ 字符串-映射到 AWSTOE 字符串类型。
+ StringList — 映射到 AWSTOE `stringList`类型。
+ SecureString — 映射到 AWSTOE 字符串类型。

有关参数存储的更多信息，请参阅*AWS Systems Manager 用户指南*中的[AWS Systems Manager 参数存储](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html)。

您也可以使用 SSM 参数`SecureString`引用 AWS Secrets Manager 密钥。例如：`{{ aws:ssm:/aws/reference/secretsmanager/test/test-secret }}`。有关更多信息，请参阅[从参数存储参数中引用 AWS Secrets Manager 密钥](https://docs.aws.amazon.com/systems-manager/latest/userguide/integration-ps-secretsmanager.html)。

**重要**  
Image Builder 从其日志中排除`SecureString`参数解析。但是，您也有责任确保敏感信息不会通过组件文档中发出的命令进行记录。例如，如果您使用带有安全字符串的`echo`命令，则该命令会将纯文本值写入日志。

### 所需的 IAM 权限
<a name="toe-ssm-parameters-permissions"></a>

要在组件中使用 Systems Manager 参数，您的实例角色必须拥有参数资源 ARN 的`ssm:GetParameter`权限。例如：

------
#### [ JSON ]

****  

```
{
	"Version":"2012-10-17",		 	 	 
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "ssm:GetParameter",
			"Resource": "arn:aws:ssm:*:111122223333:parameter/ImageBuilder-*"
		}
	]
}
```

------

要访问加密值，您还需要以下权限：
+ `kms:Decrypt`对于使用客户管理的`SecureString`参数或 AWS Secrets Manager 值进行加密，请添加 AWS KMS key。
+ `secretsmanager:GetSecretValue`如果您引用 Secrets Manager 密钥，请添加。

### 在组件文档中引用 SSM 参数
<a name="toe-ssm-parameters-example"></a>

以下示例说明如何引用组件中 Systems Manager 参数的 Systems Manager 参数存储参数：

```
name: UseSSMParameterVariable
description: This is a sample component document that prints out the value of an SSM Parameter. Never do this for a SecureString parameter.
schemaVersion: 1.0

phases:
  - name: verify
    steps:
      - name: EchoParameterValue
        action: ExecuteBash
        inputs:
          commands:
            - echo "Log SSM parameter name: /my/test/param, value {{ aws:ssm:/my/test/param }}."
```

### SSM 参数的动态运行时变量分辨率
<a name="toe-dynamic-vars"></a>

AWSTOE 提供了以下内置函数，您可以在变量引用中使用该函数在运行时操作或转换值。

#### 解析函数
<a name="toe-function-resolve"></a>

该`resolve`函数解析另一个变量引用内部的变量引用，从而允许动态变量名引用。这在使用 SSM 参数时很有用，因为其中部分参数路径可能是可变的，并作为文档参数传入。

该`resolve`函数仅支持 SSM 参数名称部分的动态解析。

##### 语法
<a name="toe-function-resolve-syntax"></a>

以下示例`dynamic_variable`中的表示 SSM 参数的名称，并且必须是以下参数之一：
+ SSM 参数参考（例如，`aws:ssm:/my/param`）
+ 组件文档参数引用（例如，`parameter-name`）

```
{{ aws:ssm:resolve(dynamic_variable) }}
```

##### 示例：在运行时解析 SSM 参数
<a name="toe-function-resolve-examples"></a>

以下示例说明如何在 YAML 组件文档中使用该`resolve`函数：

```
name: SsmParameterTest
description: This component verifies an SSM parameter variable reference with the echo command.
schemaVersion: 1.0

parameters:
  - parameter-name:
      type: string
      description: "test"

phases:
  - name: validate
    steps:
      - name: PrintDynamicVariable
        action: ExecuteBash
        inputs:
          commands:
            - echo "{{ aws:ssm:resolve(parameter-name) }}"
```

# 在中使用条件构造 AWSTOE
<a name="toe-conditional-constructs"></a>

根据指定的条件表达式的计算结果是 `true` 还是 `false`，条件构造会在组件文档中执行不同的操作。您可以使用 `if` 构造来控制组件文档中的执行流程。

## if 构造
<a name="toe-conditional-if"></a>

您可以使用 `if` 构造来评估是否应该运行某步骤。默认情况下，当 `if` 条件表达式的计算结果为 `true` 时， AWSTOE 运行该步骤，当条件表达式计算结果为 `false` 时， AWSTOE 跳过该步骤。如果跳过某个步骤，则在 AWSTOE 评估阶段和文档是否成功运行时，该步骤将被视为成功步骤。

**注意**  
即使该步骤触发了重启，也只对一个 `if` 语句进行一次计算。如果某个步骤重启，它就会识别出 `if` 语句已经进行计算，并从中断的地方继续进行。

### 语法
<a name="toe-conditional-if-syntax"></a>

```
if:
  - <conditional expression>:
      [then: <step action>]
      [else: <step action>]
```


| 键名称 | 必需 | 说明 | 
| --- | --- | --- | 
| 条件表达式 | 是 |  条件表达式可以在顶层包含以下类型的运算符之一。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/imagebuilder/latest/userguide/toe-conditional-constructs.html) 如果您的表达式必须满足多个条件，请使用逻辑运算符来指定您的条件。  | 
| then | 否 |  定义条件表达式的计算结果为 `true` 时要采取的操作。  | 
| else | 否 |  定义条件表达式的计算结果为 `false` 时要采取的操作。  | 
| 步骤操作 | 有条件 |  使用 `then` 或 `else` 时，必须指定以下步骤操作之一： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/imagebuilder/latest/userguide/toe-conditional-constructs.html)  | 

**示例 1：安装软件包**  
 AWSTOE 组件文档中的以下示例步骤使用逻辑运算符来测试参数值，并在软件包解压缩后运行相应的软件包管理器命令来安装应用程序。

```
    - name: InstallUnzipAptGet
      action: ExecuteBash
      if:
        and:
            - binaryExists: 'apt-get'
            - not:
                binaryExists: 'unzip'
      inputs:
        commands:
            - sudo apt-get update
            - sudo apt-get install -y unzip

    - name: InstallUnzipYum
      action: ExecuteBash
      if:
        and:
            - binaryExists: 'yum'
            - not:
                binaryExists: 'unzip'
      inputs:
        commands:
            - sudo yum install -y unzip

    - name: InstallUnzipZypper
      action: ExecuteBash
      if:
        and:
            - binaryExists: 'zypper'
            - not:
                binaryExists: 'unzip'
      inputs:
        commands:
            - sudo zypper refresh
            - sudo zypper install -y unzip
```

**示例 2：跳过步骤**  
以下示例显示了跳过步骤的两种方法。一种是使用逻辑运算符，另一种是结合使用比较运算符与 `Skip` 步骤操作。

```
# Creates a file if it does not exist using not
- name: CreateMyConfigFile-1
  action: ExecuteBash
  if:
    not:
      fileExists: '/etc/my_config'
  inputs:
    commands:
      - echo "Hello world" > '/etc/my_config'

# Creates a file if it does not exist using then and else
- name: CreateMyConfigFile-2
  action: ExecuteBash
  if:
    fileExists: '/etc/my_config'
    then: Skip
    else: Execute
  inputs:
    commands:
      - echo "Hello world" > '/etc/my_config'
```

# 在 AWSTOE 组件文档中使用比较运算符
<a name="toe-comparison-operators"></a>

您可以结合使用以下比较运算符与 **[Assert](toe-action-modules.md#action-modules-assertion)** 操作模块以及使用 [if 构造语法](toe-conditional-constructs.md#toe-conditional-if)的条件表达式。比较运算符可以对单个值进行比较，例如 `stringIsEmpty`，也可以将基准值与第二个值（变量值）进行比较，以确定条件表达式的计算结果是 `true` 还是 `false`。

如果对两个值进行比较，则第二个值可以是链式变量。

比较不同类型的值时，在比较之前可能会进行以下值转换：
+ 对于数值比较，如果变量值是字符串，则在计算之前将字符串 AWSTOE 转换为数字。如果无法进行转换，则比较返回 `false`。例如，如果变量值为 `"1.0"`，则可以进行转换，但如果变量值为 `"a10"`，则转换将会失败。
+ 对于字符串比较，如果变量值是一个数字，则在求值之前将其 AWSTOE 转换为字符串。

## 比较字符串
<a name="toe-compare-strings"></a>

以下比较运算符结合字符串来比较值、测试空格或空字符串，或者将输入值与正则表达式模式进行比较。字符串比较不区分大小写，也不会从字符串输入的开头或结尾去掉空格。

**字符串比较运算符**
+ [stringIsEmpty](#stringIsEmpty)
+ [stringIsWhitespace](#stringIsWhitespace)
+ [stringEquals](#stringEquals)
+ [stringLessThan](#stringLessThan)
+ [stringLessThanEquals](#stringLessThanEquals)
+ [stringGreaterThan](#stringGreaterThan)
+ [stringGreaterThanEquals](#stringGreaterThanEquals)
+ [patternMatches](#patternMatches)

**stringIsEmpty**  
如果指定的字符串不包含任何字符，则 `stringIsEmpty` 运算符将返回 `true`。例如：  

```
# Evaluates to true
stringIsEmpty: ""

# Evaluates to false
stringIsEmpty: " "
				
# Evaluates to false
stringIsEmpty: "Hello."
```

**stringIsWhitespace**  
测试为 `stringIsWhitespace` 指定的字符串是否仅包含空格。例如：  

```
# Evaluates to true
stringIsWhitespace: "   "

# Evaluates to false
stringIsWhitespace: ""
				
# Evaluates to false
stringIsWhitespace: " Hello?"
```

**stringEquals**  
测试为 `stringEquals` 指定的字符串是否与 `value` 参数中指定的字符串完全匹配。例如：  

```
# Evaluates to true
stringEquals: 'Testing, testing...'
value: 'Testing, testing...'

# Evaluates to false
stringEquals: 'Testing, testing...'
value: 'Hello again.'

# Evaluates to false
stringEquals: 'Testing, testing...'
value: 'TESTING, TESTING....'

# Evaluates to false
stringEquals: 'Testing, testing...'
value: '   Testing, testing...'
				
# Evaluates to false
stringEquals: 'Testing, testing...'
value: 'Testing, testing...   '
```

**stringLessThan**  
测试为 `stringLessThan` 指定的字符串是否小于 `value` 参数中指定的字符串。例如：  

```
# Evaluates to true
# This comparison operator isn't case sensitive
stringlessThan: 'A'
value: 'a'

# Evaluates to true - 'a' is less than 'b'
stringlessThan: 'b'
value: 'a'

# Evaluates to true
# Numeric strings compare as less than alphabetic strings
stringlessThan: 'a'
value: '0'

# Evaluates to false
stringlessThan: '0'
value: 'a'
```

**stringLessThan等于**  
测试为 `stringLessThanEquals` 指定的字符串是否小于或等于 `value` 参数中指定的字符串。例如：  

```
# Evaluates to true - 'a' is equal to 'a'
stringLessThanEquals: 'a'
value: 'a'

# Evaluates to true - since the comparison isn't case sensitive, 'a' is equal to 'A'
stringLessThanEquals: 'A'
value: 'a'

# Evaluates to true - 'a' is less than 'b'
stringLessThanEquals: 'b'
value: 'a'

# Evaluates to true - '0' is less than 'a'
stringLessThanEquals: 'a'
value: '0'

# Evaluates to false - 'a' is greater than '0'
stringLessThanEquals: '0'
value: 'a'
```

**stringGreaterThan**  
测试为 `stringGreaterThan` 指定的字符串是否大于 `value` 参数中指定的字符串。例如：  

```
# Evaluates to false - since the comparison isn't case sensitive, 'A' is equal to 'a'
stringGreaterThan: 'a'
value: 'A'

# Evaluates to true - 'b' is greater than 'a'
stringGreaterThan: 'a'
value: 'b'

# Evaluates to true - 'a' is greater than '0'
stringGreaterThan: '0'
value: 'a'

# Evaluates to false - '0' is less than 'a'
stringGreaterThan: 'a'
value: '0'
```

**stringGreaterThan等于**  
测试为 `stringGreaterThanEquals` 指定的字符串是否大于或等于 `value` 参数中指定的字符串。例如：  

```
# Evaluates to true - 'a' is equal to 'A'
stringGreaterThanEquals: 'A'
value: 'a'

# Evaluates to true - 'b' is greater than 'a'
stringGreaterThanEquals: 'a'
value: 'b'

# Evaluates to true - 'a' is greater than '0'
stringGreaterThanEquals: '0'
value: 'a'

# Evaluates to false - '0' is less than 'a'
stringGreaterThanEquals: 'a'
value: '0'
```

**patternMatches**  
测试 `value` 参数中指定的字符串是否与为 `patternMatches` 指定的正则表达式模式匹配。比较使用符合语法的 [Golang regexp 包](https://pkg.go.dev/regexp)。 RE2 有关 RE2 规则的更多信息，请参阅中的 [google/re2](https://github.com/google/re2/wiki/Syntax) 存储库。*GitHub*  
以下示例显示了返回 `true` 的模式匹配：  

```
patternMatches: '^[a-z]+$'
value: 'ThisIsValue'
```

## 比较数字
<a name="toe-compare-numbers"></a>

以下比较运算符适用于数字。根据 YAML 规范，为这些运算符提供的值必须是以下类型之一。对数字比较的支持使用 golang big 包比较运算符，例如：[func (\$1Float) Cmp](https://pkg.go.dev/math/big#Float.Cmp)。
+ 整数
+ Float（基于 float64，支持从 -1.7e\$1308 到 \$11.7e\$1308 之间的数字）
+ 与以下正则表达式模式相匹配的字符串：`^[-+]?([0-9]+[.])?[0-9]+$`

**数字比较运算符**
+ [numberEquals](#numberEquals)
+ [numberLessThan](#numberLessThan)
+ [numberLessThanEquals](#numberLessThanEquals)
+ [numberGreaterThan](#numberGreaterThan)
+ [numberGreaterThanEquals](#numberGreaterThanEquals)

**numberEquals**  
测试为 `numberEquals` 指定的数字是否等于 `value` 参数中指定的数字。以下所有示例的比较均返回 `true`：  

```
# Values provided as a positive number
numberEquals: 1
value: 1

# Comparison value provided as a string
numberEquals: '1'
value: 1

# Value provided as a string
numberEquals: 1
value: '1'

# Values provided as floats
numberEquals: 5.0
value: 5.0

# Values provided as a negative number
numberEquals: -1
value: -1
```

**numberLessThan**  
测试为 `numberLessThan` 指定的数字是否小于 `value` 参数中指定的数字。例如：  

```
# Evaluates to true
numberLessThan: 2
value: 1

# Evaluates to true
numberLessThan: 2
value: 1.9

# Evaluates to false
numberLessThan: 2
value: '2'
```

**numberLessThan等于**  
测试为 `numberLessThanEquals` 指定的数字是否小于或等于 `value` 参数中指定的数字。例如：  

```
# Evaluates to true
numberLessThanEquals: 2
value: 1

# Evaluates to true
numberLessThanEquals: 2
value: 1.9

# Evaluates to true
numberLessThanEquals: 2
value: '2'

# Evaluates to false
numberLessThanEquals: 2
value: 2.1
```

**numberGreaterThan**  
测试为 `numberGreaterThan` 指定的数字是否大于 `value` 参数中指定的数字。例如：  

```
# Evaluates to true
numberGreaterThan: 1
value: 2

# Evaluates to true
numberGreaterThan: 1
value: 1.1

# Evaluates to false
numberGreaterThan: 1
value: '1'
```

**numberGreaterThan等于**  
测试为 `numberGreaterThanEquals` 指定的数字是否大于或等于 `value` 参数中指定的数字。例如：  

```
# Evaluates to true
numberGreaterThanEquals: 1
value: 2

# Evaluates to true
numberGreaterThanEquals: 1
value: 1.1

# Evaluates to true
numberGreaterThanEquals: 1
value: '1'

# Evaluates to false
numberGreaterThanEquals: 1
value: 0.8
```

## 检查文件
<a name="toe-check-files"></a>

以下比较运算符检查文件哈希值或检查文件或文件夹是否存在。

**文件和文件夹运算符**
+ [binaryExists](#binaryExists)
+ [fileExists](#fileExists)
+ [folderExists](#folderExists)
+ [fileMD5Equals](#fileMD5Equals)
+ [fileSHA1Equals](#fileSHA1Equals)
+ [fileSHA256Equals](#fileSHA256Equals)
+ [fileSHA512Equals](#fileSHA512Equals)

**binaryExists**  
测试应用程序在当前路径中是否可用。例如：  

```
binaryExists: 'foo'
```
在 Linux 和 macOS 系统上，对于名为的应用程序*foo*，其工作原理与以下 bash 命令相同：**type *foo* >/dev/null 2>&1**，其中**\$1? == 0**表示比较成功。  
在 Windows 系统上，对于名为的应用程序*foo*，其工作原理与**\$1LASTEXITCODE = 0**表示成功比较**& C:\$1Windows\$1System32\$1where.exe /Q *foo***的 PowerShell 命令相同。

**fileExists**  
测试指定路径上是否存在文件。您可以提供绝对路径或相对路径。如果您指定的位置存在并且是一个文件，则比较的计算结果为 `true`。例如：  

```
fileExists: '/path/to/file'
```
在 Linux 和 macOS 系统上，其工作原理与以下 bash 命令相同：**-d */path/to/file***，其中 **\$1? == 0** 表示比较成功。  
在 Windows 系统上，这与 PowerShell 命令的工作原理相同**Test-Path -Path '*C:\$1path\$1to\$1file*' -PathType 'Leaf'**。

**folderExists**  
测试指定路径上是否存在文件夹。您可以提供绝对路径或相对路径。如果您指定的位置存在并且是一个文件夹，则比较的计算结果为 `true`。例如：  

```
folderExists: '/path/to/folder'
```
在 Linux 和 macOS 系统上，其工作原理与以下 bash 命令相同：**-d */path/to/folder***，其中 **\$1? == 0** 表示比较成功。  
在 Windows 系统上，这与 PowerShell 命令的工作原理相同**Test-Path -Path '*C:\$1path\$1to\$1folder*' -PathType 'Container'**。

**文件MD5等于**  
测试文件的 MD5 哈希值是否等于指定值。例如：  

```
fileMD5Equals: '<MD5Hash>'
path: '/path/to/file'
```

**文件SHA1等于**  
测试文件的 SHA1 哈希值是否等于指定值。例如：  

```
fileSHA1Equals: '<SHA1Hash>'
path: '/path/to/file'
```

**文件SHA256等于**  
测试文件的 SHA256 哈希值是否等于指定值。例如：  

```
fileSHA256Equals: '<SHA256Hash>'
path: '/path/to/file'
```

**文件SHA512等于**  
测试文件的 SHA512 哈希值是否等于指定值。例如：  

```
fileSHA512Equals: '<SHA512Hash>'
path: '/path/to/file'
```

# 在 AWSTOE 组件文档中使用逻辑运算符
<a name="toe-logical-operators"></a>

您可以使用以下逻辑运算符在组件文档中添加或修改条件表达式。 AWSTOE 按条件的指定顺序计算条件表达式。有关组件文档比较运算符的更多信息，请参阅[在 AWSTOE 组件文档中使用比较运算符](toe-comparison-operators.md)。

** 和 **  
使用 `and` 运算符，您可以将两个或多个比较作为单个表达式进行计算。当列表中的所有条件都为 true 时，表达式的计算结果为 `true`。否则，表达式的计算结果为 `false`。  
**示例：**  
下面的示例执行了两个比较：字符串和数字。两个比较的结果均为 true，因此表达式的计算结果为 true。

```
and:
  - stringEquals: 'test_string'
    value: 'test_string'
  - numberEquals: 1
    value: 1
```
以下示例还执行了两个比较。第一个比较的结果为 false，此时计算停止，第二个比较被跳过。表达式的计算结果为 `false`。  

```
and:
  - stringEquals: 'test_string'
    value: 'Hello world!'
  - numberEquals: 1
    value: 1
```

**或者**  
使用 `or` 运算符，您可以将两个或多个比较作为单个表达式进行计算。当其中一个指定的比较结果为 true 时，表达式的计算结果为 `true`。如果指定比较的计算结果均不为 `true`，则表达式的计算结果为 `false`。  
**示例：**  
下面的示例执行了两个比较：字符串和数字。第一个比较的结果为 true，因此表达式的计算结果为 `true`，第二个比较被跳过。

```
or:
  - stringEquals: 'test_string'
    value: 'test_string'
  - numberEquals: 1
    value: 3
```
以下示例还执行了两个比较。第一个比较的结果为 false，计算继续进行。第二个比较的结果为 true，因此表达式的计算结果为 `true`。  

```
or:
  - stringEquals: 'test_string'
    value: 'Hello world!'
  - numberEquals: 1
    value: 1
```
在最后一个示例中，两个比较的结果均为 false，因此表达式的计算结果为 `false`。  

```
or:
  - stringEquals: 'test_string'
    value: 'Hello world!'
  - numberEquals: 1
    value: 3
```

**not**  
使用 `not` 运算符，您可以否定单个比较。如果比较的结果为 false，则表达式的计算结果为 `true`。如果比较的结果为 true，则表达式的计算结果为 `false`。  
**示例：**  
以下示例执行了字符串比较。比较的结果为 false，因此表达式的计算结果为 `true`。

```
not:
  - stringEquals: 'test_string'
    value: 'Hello world!'
```
以下示例还执行了字符串比较。比较的结果为 true，因此表达式的计算结果为 `false`。  

```
not:
  - stringEquals: 'test_string'
    value: 'test_string'
```

# 在中使用循环结构 AWSTOE
<a name="toe-looping-constructs"></a>

本部分提供了有助于您在 AWSTOE中创建循环结构的信息。循环结构定义了重复的指令序列。您可以在 AWSTOE中使用以下类型的循环结构：
+ `for` 结构 – 在有界的整数序列上迭代。
+ `forEach` 结构
  + `forEach` 使用输入列表循环 – 迭代有限的字符串集合。
  + `forEach` 带分隔列表的循环 – 迭代由分隔符连接的有限字符串集合。

**注意**  
循环结构仅支持字符串数据类型。

**Topics**
+ [引用迭代变量](#toe-loop-iteration-variables)
+ [循环结构的类型](#toe-loop-types)
+ [步骤字段](#toe-loop-step-fields)
+ [步骤和迭代输出](#toe-loop-step-output)

## 引用迭代变量
<a name="toe-loop-iteration-variables"></a>

要引用当前迭代变量的索引和值，必须在包含循环结构的步骤的输入主体中使用引用表达式 `{{ loop.* }}`。此表达式不能用于引用另一个步骤的循环结构的迭代变量。

引用表达式由以下成员组成：
+ `{{ loop.index }}` – 当前迭代的序数位置，索引为 `0`。
+ `{{ loop.value }}` – 与当前迭代变量关联的值。

### 循环名称
<a name="toe-loop-iteration-variables-names"></a>

 所有循环结构都有一个用于标识的可选名称字段。如果提供了循环名称，则可以使用它来引用步骤输入主体中的迭代变量。要引用命名循环的迭代索引和值，请在步骤的输入主体中使用带 `{{ loop.* }}` 的 `{{ <loop_name>.* }}`。此表达式不能用于引用另一个步骤的命名循环结构。

引用表达式由以下成员组成：
+ `{{ <loop_name>.index }}` – 命名循环当前迭代的序数位置，其索引位于 `0`。
+ `{{ <loop_name>.value }}` – 与命名循环的当前迭代变量关联的值。

### 解析引用表达式
<a name="toe-loop-iteration-variables-expressions"></a>

解 AWSTOE 析引用表达式如下：
+ `{{ <loop_name>.* }}`— 使用以下逻辑 AWSTOE 解析此表达式：
  + 如果当前正在运行的步骤的循环与 `<loop_name>` 值匹配，则引用表达式将解析为当前正在运行的步骤的循环结构。
  + 如果命名的循环结构出现在当前运行的步骤内，则 `<loop_name>` 解析为该结构。
+ `{{ loop.* }}`— 使用在当前运行的步骤中定义的循环结构 AWSTOE 解析表达式。

如果在不包含循环的步骤中使用引用表达式，则 AWSTOE 不会解析这些表达式，并且它们出现在步骤中而不进行替换。

**注意**  
引用表达式必须用双引号括起来，YAML 编译器才能正确解释。

## 循环结构的类型
<a name="toe-loop-types"></a>

本节提供有关可在 AWSTOE中使用的循环结构类型的信息和示例。

**Topics**
+ [`for` 循环](#toe-loop-types-for)
+ [`forEach` 使用输入列表循环](#toe-loop-types-foreach)
+ [`forEach` 使用带分隔列表的循环](#toe-loop-types-foreach-delimited)

### `for` 循环
<a name="toe-loop-types-for"></a>

该 `for` 循环迭代处于由变量开头和结尾勾勒的边界内指定的整数范围。迭代值在集合 `[start, end]` 中，包括边界值。

AWSTOE 验证`start``end`、和`updateBy`值，以确保组合不会导致无限循环。

`for` 循环架构

```
  - name: "StepName"
    action: "ActionModule"
    loop:
      name: "string"
      for:
        start: int
        end: int
        updateBy: int
inputs:
  ...
```


**`for` 循环输入**  

| 字段 | 描述 | Type | 必需 | 默认 | 
| --- | --- | --- | --- | --- | 
|  `name`  | 循环的唯一名称。与同一阶段的其他循环名称相比，它必须是唯一的。 |  字符串  |  否  |  ""  | 
|  `start`  | 迭代的起始值。不接受链接表达式。 |  整数  |  是  |  不适用  | 
| `end` | 迭代的结束值。不接受链接表达式。 | 整数 | 是 | 不适用 | 
| `updateBy` | 通过加法更新迭代值的差异。它必须是非零负值或正值。不接受链接表达式。 | 整数 | 是 | 不适用 | 

`for` 循环输入示例

```
  - name: "CalculateFileUploadLatencies"
    action: "ExecutePowerShell"
    loop:
      for:
        start: 100000
        end: 1000000
        updateBy: 100000
    inputs:
      commands:
        - |
          $f = new-object System.IO.FileStream c:\temp\test{{ loop.index }}.txt, Create, ReadWrite
          $f.SetLength({{ loop.value }}MB)
          $f.Close()
        - c:\users\administrator\downloads\latencyTest.exe --file c:\temp\test{{ loop.index }}.txt
        - AWS s3 cp c:\users\administrator\downloads\latencyMetrics.json s3://bucket/latencyMetrics.json
        - |
          Remove-Item -Path c:\temp\test{{ loop.index }}.txt
          Remove-Item -Path c:\users\administrator\downloads\latencyMetrics.json
```

### `forEach` 使用输入列表循环
<a name="toe-loop-types-foreach"></a>

该 `forEach` 循环迭代一个显式的值列表，该列表可以是字符串和链式表达式。

`forEach` 使用输入列表架构进行循环

```
  - name: "StepName"
    action: "ActionModule"
    loop:
      name: "string"
      forEach:
        - "string"
    inputs:
  ...
```


**`forEach` 使用输入列表输入进行循环**  

| 字段 | 描述 | Type | 必需 | 默认 | 
| --- | --- | --- | --- | --- | 
|  `name`  | 循环的唯一名称。与同一阶段的其他循环名称相比，它必须是唯一的。 |  字符串  |  否  |  ""  | 
|  `forEach` 循环字符串列表  |  用于迭代的字符串列表。接受链式表达式作为列表中的字符串。链式表达式必须用双引号括起来，YAML 编译器才能正确解释它们。  |  字符串列表  |  是  |  不适用  | 

`forEach` 使用输入列表循环示例 1

```
  - name: "ExecuteCustomScripts"
    action: "ExecuteBash"
    loop:
      name: BatchExecLoop
      forEach:
        - /tmp/script1.sh
        - /tmp/script2.sh
        - /tmp/script3.sh
    inputs:
      commands:
        - echo "Count {{ BatchExecLoop.index }}"
        - sh "{{ loop.value }}"
        - |
          retVal=$?
          if [ $retVal -ne 0 ]; then
            echo "Failed"
          else
            echo "Passed"
         fi
```

`forEach` 使用输入列表循环示例 2

```
  - name: "RunMSIWithDifferentArgs"
    action: "ExecuteBinary"
    loop:
      name: MultiArgLoop
      forEach:
        - "ARG1=C:\Users ARG2=1"
        - "ARG1=C:\Users"
        - "ARG1=C:\Users ARG3=C:\Users\Administrator\Documents\f1.txt"
    inputs:
      commands:
        path: "c:\users\administrator\downloads\runner.exe"
        args:
          - "{{ MultiArgLoop.value }}"
```

`forEach` 使用输入列表循环示例 3

```
  - name: "DownloadAllBinaries"
    action: "S3Download"
    loop:
      name: MultiArgLoop
      forEach:
        - "bin1.exe"
        - "bin10.exe"
        - "bin5.exe"
    inputs:
      - source: "s3://bucket/{{ loop.value }}"
        destination: "c:\temp\{{ loop.value }}"
```

### `forEach` 使用带分隔列表的循环
<a name="toe-loop-types-foreach-delimited"></a>

该循环遍历包含由分隔符分隔的值的字符串。要遍历字符串的组成部分，请 AWSTOE 使用分隔符将字符串拆分为适合迭代的数组。

`forEach` 使用分隔列表架构的循环

```
  - name: "StepName"
    action: "ActionModule"
    loop:
      name: "string"
      forEach:
        list: "string"
        delimiter: ".,;:\n\t -_"
    inputs:
  ...
```


**`forEach` 使用分隔列表输入的循环**  

| 字段 | 描述 | Type | 必需 | 默认 | 
| --- | --- | --- | --- | --- | 
|  `name`  | 赋予循环的唯一名称。与同一阶段的其他循环名称相比，它应该是唯一的。 |  字符串  |  否  |  ""  | 
|  `list`  | 由组成字符串组成的字符串，这些字符串由一个通用分隔符连接在一起。也接受链式表达式。如果是链式表达式，请确保用双引号将它们括起来，以便 YAML 编译器正确解释。 | 字符串 |  是  |  不适用  | 
| `delimiter` | 用于在区块中分隔字符串的字符。默认为逗号字符。在给定的列表中只允许使用一个分隔符：[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/imagebuilder/latest/userguide/toe-looping-constructs.html) 不能使用链接表达式。 | 字符串 | 否 | 逗号："," | 

**注意**  
`list` 的值被视为不可变的字符串。如果在运行时更改了 `list` 的源，则它在运行期间不会反映出来。

`forEach` 使用分隔列表循环示例 1

此示例使用以下链接表达式模式来引用另一个步骤的输出：`<phase_name>.<step_name>.[inputs | outputs].<var_name>`。

```
  - name: "RunMSIs"
    action: "ExecuteBinary"
    loop:
      forEach:
        list: "{{ build.GetAllMSIPathsForInstallation.outputs.stdout }}"
        delimiter: "\n"
    inputs:
      commands:
        path: "{{ loop.value }}"
```

`forEach` 使用分隔列表循环示例 2

```
  - name: "UploadMetricFiles"
    action: "S3Upload"
    loop:
      forEach:
        list: "/tmp/m1.txt,/tmp/m2.txt,/tmp/m3.txt,..."
    inputs:
      commands:
        - source: "{{ loop.value }}"
          destination: "s3://bucket/key/{{ loop.value }}"
```

## 步骤字段
<a name="toe-loop-step-fields"></a>

循环是步骤的一部分。任何与步骤运行相关的字段都不会应用于单个迭代。步骤字段仅应用于步骤级别，如下所示：
+ *timeoutSeconds* – 循环的所有迭代都必须在此字段指定的时间段内运行。如果循环运行超时，则 AWSTOE 运行该步骤的重试策略，并为每次新的尝试重置超时参数。如果循环运行在达到最大重试次数后超过超时值，则该步骤的失败消息将表明循环运行已超时。
+ *onFailure* – 对步骤应用失败处理，如下所示：
  + 如果 *onFa* ilure 设置为`Abort`，则 AWSTOE 退出循环并根据重试策略重试该步骤。在达到最大重试次数后，将当前步骤 AWSTOE 标记为失败，并停止运行该进程。

    AWSTOE 将父阶段和文档的状态码设置为`Failed`。
**注意**  
在失败的步骤之后，不再运行任何其他步骤。
  + 如果 *onFailure* 设置为 `Continue`，则 AWSTOE 退出循环并根据重试策略重试该步骤。在达到最大重试次数后，将当前步骤 AWSTOE 标记为失败，然后继续运行下一个步骤。

    AWSTOE 将父阶段和文档的状态码设置为`Failed`。
  + 如果 *onFailure* 设置为 `Ignore`，则 AWSTOE 退出循环并根据重试策略重试该步骤。在达到最大重试次数后，将当前步骤 AWSTOE 标记为`IgnoredFailure`，然后继续运行下一步。

    AWSTOE 将父阶段和文档的状态码设置为`SuccessWithIgnoredFailure`。
**注意**  
这仍被视为成功运行，但包含一些信息，可让您知道一个或多个步骤失败并被忽略。
+ *maxAttempts * – 每次重试，整个步骤和所有迭代都是从头开始运行的。
+ *状态* – 步骤运行的总体状态。`status` 不代表各个迭代的状态。包含循环的步骤状态确定如下：
  + 如果单个迭代运行失败，则步骤的状态指向失败。
  + 如果所有迭代都成功，则步骤的状态指向成功。
+ *startTime * – 步骤运行的总开始时间。不代表各个迭代的开始时间。
+ *endTime * – 步骤运行的总结束时间。不代表单个迭代的结束时间。
+ *failureMessage * – 包括在出现非超时错误时失败的迭代索引。如果出现超时错误，消息指出该循环运行失败。为了最大限度地减少失败消息的大小，不为每次迭代提供单独的错误消息。

## 步骤和迭代输出
<a name="toe-loop-step-output"></a>

每次迭代都包含一个输出。在循环运行结束时， AWSTOE 将所有成功的迭代输出合并到中。`detailedOutput.json`合并输出是属于相应输出键的值的排序规则，这些值在操作模块的输出架构中定义。下面的示例说明如何合并输出：

**迭代 1 的 `ExecuteBash` 的输出**

```
{
	"stdout":"Hello"
}
```

**迭代 2 的 `ExecuteBash` 的输出**

```
{
	"stdout":"World"
}
```

**步骤的 `ExecuteBash` 的输出**

```
{
	"stdout":"Hello\nWorld"
}
```

例如，`ExecuteBash`、`ExecutePowerShell` 和 `ExecuteBinary` 是操作模块，其返回 `STDOUT` 作为操作模块输出。`STDOUT` 消息与换行符连接以在 `detailedOutput.json` 中生成步骤的总体输出。

AWSTOE 不会合并失败迭代的输出。