

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

# Amazon CloudFormation 语言扩展支持
<a name="sam-specification-language-extensions"></a>

 Amazon SAMCLI支持使用`AWS::LanguageExtensions`变换的模板，包括`Fn::ForEach``Fn::Length`、`Fn::ToJsonString`、`Fn::FindInMap`和`DefaultValue`。有关这些构造的完整参考信息，请参阅《*Amazon CloudFormation 用户指南》*中的 t [AWS::LanguageExtensions r](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/transform-aws-languageextensions.html) ansform。

要在 Amazon SAM 模板中使用语言扩展名，*请在之前的`Transform`部分`AWS::LanguageExtensions`中列出*`AWS::Serverless-2016-10-31`：

```
Transform:
  - AWS::LanguageExtensions
  - AWS::Serverless-2016-10-31
```

当在模板的`Transform`部分`AWS::LanguageExtensions`中 Amazon SAMCLI检测到*并且*您选择了本地处理时，它会在运行 Amazon SAM 转换之前在本地扩展语言扩展结构。这使`sam build`得`sam package`、`sam deploy`、`sam sync`、`sam validate`、`sam local invoke`、`sam local start-api`、和`sam local start-lambda`能够使用使用这些构造的模板。

默认情况下，本地处理处于关闭状态。禁用后， Amazon SAMCLI会将模板保持不变，并在部署时 Amazon CloudFormation 处理服务器端的`AWS::LanguageExtensions`转换。有关激活方法，请参阅[启用语言扩展](#sam-specification-language-extensions-enabling)。

启用后，扩展分两个阶段进行：

1. **第 1 阶段（语言扩展）**— 扩展`Fn::ForEach`循环，尽可能解析内部函数，并将模板转换为标准模板。 Amazon CloudFormation

1. **第 2 阶段（Amazon SAM 转换）**-扩展后的模板将像往常一样由 Amazon SAM 翻译器处理。

由于在服务器端 Amazon CloudFormation 处理了`AWS::LanguageExtensions`转换，因此保留了原始模板（`Fn::ForEach`完好无损）以供 Amazon CloudFormation 部署。

## 启用语言扩展
<a name="sam-specification-language-extensions-enabling"></a>

按命令选择`AWS::LanguageExtensions`进行本地处理。有三种等效的激活方法，按优先级顺序列出：

1. CLIfla@@ **g** — 传递`--language-extensions`一次调用：

   ```
   sam build --language-extensions
   sam package --language-extensions ...
   sam deploy --language-extensions ...
   ```

   `--no-language-extensions`显式禁用，覆盖两者`samconfig.toml`以及下面描述的环境变量。

1. **`samconfig.toml`**— 坚持每个项目的选择：

   ```
   [default.build.parameters]
   language_extensions = true
   
   [default.package.parameters]
   language_extensions = true
   
   [default.deploy.parameters]
   language_extensions = true
   
   [default.sync.parameters]
   language_extensions = true
   
   [default.local_invoke.parameters]
   language_extensions = true
   
   [default.local_start_api.parameters]
   language_extensions = true
   
   [default.local_start_lambda.parameters]
   language_extensions = true
   
   [default.validate.parameters]
   language_extensions = true
   ```

   一个`samconfig.toml`条目是作为命令的默认值加载的，因此它会像传递标志一样生效，因此胜过环境变量。

1. **环境变量** — 设置为`SAM_CLI_ENABLE_LANGUAGE_EXTENSIONS=1`对当前 shell 启用：

   ```
   export SAM_CLI_ENABLE_LANGUAGE_EXTENSIONS=1
   sam build
   sam local invoke MyFunction
   ```

   真值（不区分大小写）是`1`、`true`和。`yes`其他任何内容，包括空字符串，都被视为关闭。只有当既没有CLI标记也没有`samconfig.toml`设置值时，才会参考环境变量。

**重要**  
每个命令都需要自己激活。传递`--language-extensions`给`sam build`不会传播到以后的版本 `sam local invoke` ——本地处理是由每个命令调用决定的。使用环境变量或`samconfig.toml`条目在命令之间启用，而无需重复该标志。

## Fn:: ForEach
<a name="sam-specification-language-extensions-foreach"></a>

`Fn::ForEach`根据单个模板定义生成多个资源、条件或输出：

```
Transform:
  - AWS::LanguageExtensions
  - AWS::Serverless-2016-10-31

Parameters:
  ServiceNames:
    Type: CommaDelimitedList
    Default: "Users,Orders,Products"

Resources:
  Fn::ForEach::Services:
    - Name
    - !Ref ServiceNames
    - ${Name}Function:
        Type: AWS::Serverless::Function
        Properties:
          Handler: index.handler
          Runtime: python3.12
          CodeUri: ./services/${Name}
```

Run `sam build` ning 将其扩展为`UsersFunction``OrdersFunction``ProductsFunction`、和，每个都从其各自的源目录构建。

### 动态构件属性
<a name="sam-specification-language-extensions-dynamic-artifacts"></a>

当可打包属性使用循环变量（例如`./services/${Name}`）时， Amazon SAMCLI会生成一个将每个集合值映射到其 Amazon S3 的 Amazon CloudFormation `Mappings`部分。URI正`Fn::ForEach`文被重写为使用，`Fn::FindInMap`因此 Amazon CloudFormation 可以在部署时解析正确的工件。

已识别的工件属性与当今`sam package`重写的属性相同。这包括：


**可识别的动态构件属性 Amazon SAM CLI**  

| 资源类型 | 属性 | 
| --- | --- | 
| `AWS::Serverless::Function` | `CodeUri`, `ImageUri` | 
| `AWS::Serverless::LayerVersion` | `ContentUri` | 
| `AWS::Serverless::Api` | `DefinitionUri` | 
| `AWS::Serverless::HttpApi` | `DefinitionUri` | 
| `AWS::Serverless::StateMachine` | `DefinitionUri` | 
| `AWS::Serverless::GraphQLApi` | `SchemaUri`, `CodeUri` | 
| `AWS::Serverless::Application` | `Location` | 
| `AWS::Lambda::Function` | `Code`, `Code.ImageUri` | 
| `AWS::Lambda::LayerVersion` | `Content` | 
| `AWS::ApiGateway::RestApi` | `BodyS3Location` | 
| `AWS::ApiGatewayV2::Api` | `BodyS3Location` | 
| `AWS::AppSync::GraphQLSchema` | `DefinitionS3Location` | 
| `AWS::AppSync::Resolver` | `RequestMappingTemplateS3Location`, `ResponseMappingTemplateS3Location`, `CodeS3Location` | 
| `AWS::AppSync::FunctionConfiguration` | `RequestMappingTemplateS3Location`, `ResponseMappingTemplateS3Location`, `CodeS3Location` | 
| `AWS::StepFunctions::StateMachine` | `DefinitionS3Location` | 
| `AWS::ElasticBeanstalk::ApplicationVersion` | `SourceBundle` | 
| `AWS::Glue::Job` | `Command.ScriptLocation` | 
| `AWS::CloudFormation::Stack` | `TemplateURL` | 
| `AWS::CloudFormation::StackSet` | `TemplateURL` | 
| `AWS::CloudFormation::ModuleVersion` | `ModulePackage` | 
| `AWS::CloudFormation::ResourceVersion` | `SchemaHandlerPackage` | 

对于点状属性（例如，`Command.ScriptLocation`on `AWS::Glue::Job` 或 `Code.ImageUri` on`AWS::Lambda::Function`），将在资源上的嵌套位置读取和写入该值。生成的映射名称仅使用属性路径的叶段。

当属性采用循环模板化时，映射名称为`SAM<LeafProperty><LoopName>`（例如，`SAMCodeUriServices`或）。`SAMScriptLocationJobs`

**重要**  
Customer-authored 映射不应以这些`SAM*`前缀开头，而是保留给的。 Amazon SAMCLI请参阅[限制](#sam-specification-language-extensions-limitations)。

例如，之后`sam package`：

```
Mappings:
  SAMCodeUriServices:
    Users:
      CodeUri: s3://my-bucket/abc123
    Orders:
      CodeUri: s3://my-bucket/def456
    Products:
      CodeUri: s3://my-bucket/ghi789

Resources:
  Fn::ForEach::Services:
    - Name
    - !Ref ServiceNames
    - ${Name}Function:
        Type: AWS::Serverless::Function
        Properties:
          Handler: index.handler
          Runtime: python3.12
          CodeUri: !FindInMap [SAMCodeUriServices, !Ref Name, CodeUri]
```

### 每个 ForEach 机构有多种资源
<a name="sam-specification-language-extensions-multiple-resources"></a>

单个`Fn::ForEach`主体每次迭代可以发射多个资源。每个资源都是为每个集合值生成的：

```
Resources:
  Fn::ForEach::Tables:
    - TableName
    - [Users, Orders, Products]
    - ${TableName}Table:
        Type: AWS::DynamoDB::Table
        Properties:
          TableName: !Sub "${AWS::StackName}-${TableName}"
          # ...

      ${TableName}StreamProcessor:
        Type: AWS::Serverless::Function
        Properties:
          CodeUri: stream-processors/${TableName}/
          Events:
            DDBStream:
              Type: DynamoDB
              Properties:
                Stream: !GetAtt
                  - !Sub "${TableName}Table"
                  - StreamArn
```

### 映射名称冲突解决方案
<a name="sam-specification-language-extensions-mapping-collisions"></a>

当同一个`Fn::ForEach`主体中的两个资源声明相同的动态构件属性（例如，一个`Api`和一个`StateMachine`用途`DefinitionUri`）时，会 Amazon SAMCLI附加一个取自资源 Logical-ID 模板静态部分的后缀，以保持映射名称的唯一性：


**使用碰撞后缀映射名称的示例**  

| 资源模板 | 属性 | 映射名称 | 
| --- | --- | --- | 
| `${Svc}Api` | `DefinitionUri` | `SAMDefinitionUriServicesApi` | 
| `${Svc}StateMachine` | `DefinitionUri` | `SAMDefinitionUriServicesStateMachine` | 

如果没有碰撞，则使用基本名称（例如`SAMDefinitionUriServices`）。

### Parameter-based 集合
<a name="sam-specification-language-extensions-parameter-collections"></a>

如果`Fn::ForEach`集合是参数引用（例如`!Ref ServiceNames`），而循环体使用动态构件属性（例如`CodeUri: ./services/${Name}`），则 Amazon SAMCLI需要集合值来生成中所[动态构件属性](#sam-specification-language-extensions-dynamic-artifacts)述的`SAM*`映射。它在处理模板时会解析它们，来自：

1. `--parameter-overrides`传递给 Amazon SAMCLI命令。

1. 模板中参数的`Default`值。

**重要**  
由于`SAM*`映射是在打包时生成的，因此无论何时更改参数值（例如，添加新服务时），都必须重新打包，这样 Mappings 就会包含新值的条目。这仅适用于参数驱动动态构件循环；其他参数覆盖可以像往常一样在部署时更改。

```
# Package with the values you intend to deploy with
sam package --language-extensions --parameter-overrides ServiceNames="Users,Orders,Products"

# Deploy with the same values
sam deploy --language-extensions --parameter-overrides ServiceNames="Users,Orders,Products"
```

### 嵌套堆栈
<a name="sam-specification-language-extensions-nested-stacks"></a>

`Fn::ForEach`支持嵌套堆栈模板 (`AWS::CloudFormation::Stack`)。将父堆栈的`Parameters`属性 Amazon SAMCLI传递给子模板扩展，因此引用父级提供的参数的子`Fn::ForEach`集合可以正确解析。

```
# parent.yaml
Resources:
  ChildStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./child.yaml
      Parameters:
        ServiceNames: "Users,Orders,Products"
```

### 嵌套 Fn:: ForEach
<a name="sam-specification-language-extensions-nested-foreach"></a>

最多支持 5 个嵌套级别，符合 Amazon CloudFormation 限制：

```
Resources:
  Fn::ForEach::Envs:
    - Env
    - [Dev, Staging, Prod]
    - Fn::ForEach::Services:
        - Svc
        - [Users, Orders]
        - ${Env}${Svc}Function:
            Type: AWS::Serverless::Function
            Properties:
              CodeUri: ./services/${Svc}
              Environment:
                Variables:
                  STAGE: ${Env}
```

### ForEach 在输出中
<a name="sam-specification-language-extensions-foreach-outputs"></a>

`Fn::ForEach`区块也会在该`Outputs`部分内展开，因此你可以为每个集合值发出一个输出：

```
Outputs:
  Fn::ForEach::FunctionArns:
    - Name
    - [alpha, beta]
    - ${Name}FunctionArn:
        Value: !GetAtt
          - !Sub "${Name}Function"
          - Arn
```

### 条件和 DependsOn
<a name="sam-specification-language-extensions-conditions-dependson"></a>

发出的资源`Fn::ForEach`可以携带，`Condition`并且可以`DependsOn`像任何其他资源一样携带。条件或依赖关系会复制到每个生成的资源上：

```
Conditions:
  IsProd: !Equals [!Ref Environment, prod]

Resources:
  SharedTable:
    Type: AWS::DynamoDB::Table
    # ...

  Fn::ForEach::Functions:
    - Name
    - [api, worker]
    - ${Name}Function:
        Type: AWS::Serverless::Function
        Condition: IsProd
        DependsOn: SharedTable
        Properties:
          Handler: main.handler
          CodeUri: functions/${Name}/
```

### &amp;{标识符} 语法
<a name="sam-specification-language-extensions-identifier-syntax"></a>

该`&{identifier}`语法从替换值中去除非字母数字字符，这对于从 IP 地址等值生成有效的逻辑 ID 非常有用：

```
Fn::ForEach::Hosts:
  - IP
  - ["10.0.0.1", "10.0.0.2"]
  - Host&{IP}:
      Type: AWS::EC2::Instance
      # Expands to Host10001, Host10002
```

## 支持的内部函数
<a name="sam-specification-language-extensions-supported-functions"></a>

在扩展过程中，以下内部函数将在本地解析：


**在语言扩展扩展期间本地解析的内部函数**  

| 函数 | 说明 | 
| --- | --- | 
| `Fn::ForEach` | 循环扩展。 | 
| `Fn::Length` | 返回列表元素的数量。 | 
| `Fn::ToJsonString` | 将值转换为字符JSON串。 | 
| `Fn::FindInMap` | 地图查询，包括可选的`DefaultValue`。 | 
| `Fn::If` | 条件值选择。 | 
| `Fn::Sub` | 字符串替换。 | 
| `Fn::Join` | 字符串连接。 | 
| `Fn::Split` | 字符串拆分。 | 
| `Fn::Select` | 列表元素选择。 | 
| `Fn::Base64` | Base64 编码。 | 
| `Fn::Equals`, `Fn::And`, `Fn::Or`, `Fn::Not` | 状况评估。 | 
| `Ref` | 参数和伪参数引用。 | 

需要部署资源（`Fn::GetAtt`、`Fn::ImportValue`、`Fn::GetAZs`）的函数会被保留， Amazon CloudFormation 以便在部署时解析。

## 验证错误
<a name="sam-specification-language-extensions-validation-errors"></a>

在 Amazon SAM 转换运行之前，会在本地捕获以下模板问题：


**扩展语言时出现验证错误**  

| 原因 | 错误消息 | 
| --- | --- | 
| 该`Fn::ForEach`值格式不正确 — 不是列表、不完全包含 3 个元素或具有非字符串循环标识符。 | `Fn::ForEach::<key> layout is incorrect`（提高为`InvalidTemplateException`）。 | 
| 嵌套了超过 5 `Fn::ForEach` 个级别。 | `Fn::ForEach nesting depth of <N> exceeds the maximum allowed depth of 5. CloudFormation supports up to 5 nested Fn::ForEach loops.` | 
| 集合解析为空列表（例如，带的`CommaDelimitedList`参数`Default: ""`）。 | 没有错误 — 循环被静默跳过，并且不会发出任何资源。 | 
| 集合`!Ref`中的指向模板中未声明的参数。 | 没有错误 — 未解析的引用保留在模板中。在部署时， Amazon CloudFormation 将在服务器端解决这个问题。 | 

## 限制
<a name="sam-specification-language-extensions-limitations"></a>
+ **集合必须是可解析 build/package 的。** `Fn::ForEach`使用`Fn::GetAtt``Fn::ImportValue`、或 SSM/Secrets Manager 动态引用的集合无法在本地展开。请`--parameter-overrides`改用带的参数。
+ **动态构件映射在打包时已修复。**当`Fn::ForEach`集合是参数引用并且循环主体使用动态构件属性（例如`CodeUri: ./services/${Name}`）时，生成的`SAM*`映射仅包含在打包时解析的参数值的条目。如果您在部署时更改`--parameter-overrides`该参数而不重新打包，则新值将没有映射条目，部署将失败。这不适用于不用于驱动动态构件的参数`Fn::ForEach`。
+ **`DeletionPolicy`并在**扩展过程中`UpdateReplacePolicy`经过验证和解决。它们支持参数`Ref`，但不支持其他内部函数。
+ **嵌套限制。**最多`Fn::ForEach`可以嵌套 5 个级别，与 Amazon CloudFormation 服务器端的限制相匹配。
+ **保留的映射名称。**以以下任一名称开头的映射名称是为保留的 Amazon SAMCLI — 请勿使用这些前缀创作自己的映射：
  + `SAMCodeUri`、`SAMImageUri`、`SAMContentUri`、`SAMDefinitionUri`、`SAMSchemaUri`、`SAMBodyS3Location`、`SAMDefinitionS3Location`、`SAMTemplateURL`、`SAMCode`、`SAMContent` — `sam package` 为动态构件属性发出。参见[动态构件属性](#sam-specification-language-extensions-dynamic-artifacts)表格。
  + `SAMLayers`— 由`Fn::ForEach`生成的函数获取自动生成的依赖层引用（Lambda 将构建分层到嵌套堆栈中）`sam build`时发出。 Amazon SAMCLI此前缀没有相应的用户创作属性；它是自动添加的。

## 遥测
<a name="sam-specification-language-extensions-telemetry"></a>

当使用`--language-extensions`（或 Amazon SAMCLI其等效环境变量）调用命令*并且*模板声明转换时，会发出`CFNLanguageExtensions`遥测事件。`AWS::LanguageExtensions`该事件每次调用都会触发一次，并且不会传输任何模板内容。本地处理处于关闭状态（默认）时，不会触发任何事件。