Exemplos de Fn::ForEach
na seção Resources
Estes exemplos demonstram o uso da função intrínseca Fn::ForEach
na seção Sintaxe de Resources de modelo do CloudFormation.
Tópicos
Replicar um recurso do Amazon SNS
Este trecho de exemplo retorna uma lista de quatro tópicos do Amazon SNS, com o ID lógico correspondente aos itens na coleção (Success
, Failure
, Timeout
, Unknown
), com um TopicName
correspondente e FifoTopic
definido como true
.
JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::LanguageExtensions", "Parameters": { "pRepoARNs": { "Description": "ARN of SSO instance", "Type": "CommaDelimitedList" } }, "Resources": { "Fn::ForEach::Topics": [ "TopicName", { "Ref": "pRepoARNs" }, { "SnsTopic${TopicName}": { "Type": "AWS::SNS::Topic", "Properties": { "TopicName": { "Fn::Join": [ ".", [ { "Ref": "TopicName" }, "fifo" ] ] }, "FifoTopic": true } } } ] } }
YAML
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Parameters: pRepoARNs: Description: ARN of SSO instance Type: CommaDelimitedList Resources: 'Fn::ForEach::Topics': - TopicName - !Ref pRepoARNs - 'SnsTopic${TopicName}': Type: 'AWS::SNS::Topic' Properties: TopicName: 'Fn::Join': - '.' - - !Ref TopicName - fifo FifoTopic: true
O modelo transformado será equivalente ao modelo a seguir:
{ "AWSTemplateFormatVersion": "2010-09-09", "Resources": { "SnsTopicSuccess": { "Type": "AWS::SNS::Topic", "Properties": { "TopicName": "Success.fifo", "FifoTopic": true } }, "SnsTopicFailure": { "Type": "AWS::SNS::Topic", "Properties": { "TopicName": "Failure.fifo", "FifoTopic": true } }, "SnsTopicTimeout": { "Type": "AWS::SNS::Topic", "Properties": { "TopicName": "Timeout.fifo", "FifoTopic": true } }, "SnsTopicUnknown": { "Type": "AWS::SNS::Topic", "Properties": { "TopicName": "Unknown.fifo", "FifoTopic": true } } } }
Replicar um recurso do Amazon DynamoDB
Este trecho de exemplo cria quatro recursos AWS::DynamoDB::Table
com nomes como Points
, Score
, etc.
JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::LanguageExtensions", "Resources": { "Fn::ForEach::Tables": [ "TableName", ["Points", "Score", "Name", "Leaderboard"], { "DynamoDB${TableName}": { "Type": "AWS::DynamoDB::Table", "Properties": { "TableName": { "Ref": "TableName" }, "AttributeDefinitions": [ { "AttributeName": "id", "AttributeType": "S" } ], "KeySchema": [ { "AttributeName": "id", "KeyType": "HASH" } ], "ProvisionedThroughput": { "ReadCapacityUnits": "5", "WriteCapacityUnits": "5" } } } } ] } }
YAML
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Resources: 'Fn::ForEach::Tables': - TableName - [Points, Score, Name, Leaderboard] - 'DynamoDB${TableName}': Type: 'AWS::DynamoDB::Table' Properties: TableName: !Ref TableName AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: '5' WriteCapacityUnits: '5'
O modelo transformado será equivalente ao modelo a seguir:
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Resources: DynamoDBPoints: Type: 'AWS::DynamoDB::Table' Properties: TableName: Points AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: '5' WriteCapacityUnits: '5' DynamoDBScore: Type: 'AWS::DynamoDB::Table' Properties: TableName: Score AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: '5' WriteCapacityUnits: '5' DynamoDBName: Type: 'AWS::DynamoDB::Table' Properties: TableName: Name AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: '5' WriteCapacityUnits: '5' DynamoDBLeaderboard: Type: 'AWS::DynamoDB::Table' Properties: TableName: Leaderboard AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: '5' WriteCapacityUnits: '5'
Replicar vários recursos
Este exemplo cria várias instâncias de AWS::EC2::NatGateway
e AWS::EC2::EIP
usando uma convenção de nomenclatura de “{ResourceType}${Identifier}”. É possível declarar vários tipos de recursos em um loop Fn::ForEach
para usar um único identificador.
nota
O exemplo abaixo pressupõe que as condições TwoNatGateways
e ThreeNatGateways
existam e que os recursos PublicSubnetA
, PublicSubnetB
e PublicSubnetC
estejam definidos.
nota
Valores exclusivos para cada elemento na coleção são definidos na seção Mapeamentos, onde a função intrínseca Fn::FindInMap é usada para referenciar o valor correspondente. Se Fn::FindInMap
não for capaz de encontrar o identificador correspondente, a propriedade Condição não será definida como resolvendo para !Ref
‘AWS:::NoValue
.
JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::LanguageExtensions", "Mappings": { "NatGateway": { "Condition": { "B": "TwoNatGateways", "C": "ThreeNatGateways" } } }, "Resources": { "Fn::ForEach::NatGatewayAndEIP": [ "Identifier", [ "A", "B", "C" ], { "NatGateway${Identifier}": { "Type": "AWS::EC2::NatGateway", "Properties": { "AllocationId": { "Fn::GetAtt": [ { "Fn::Sub": "NatGatewayAttachment${Identifier}" }, "AllocationId" ] }, "SubnetId": { "Ref": { "Fn::Sub": "PublicSubnet${Identifier}" } } }, "Condition": { "Fn::FindInMap": [ "NatGateway", "Condition", { "Ref": "Identifier" }, { "DefaultValue": { "Ref": "AWS::NoValue" } } ] } }, "NatGatewayAttachment${Identifier}": { "Type": "AWS::EC2::EIP", "Properties": { "Domain": "vpc" }, "Condition": { "Fn::FindInMap": [ "NatGateway", "Condition", { "Ref": "Identifier" }, { "DefaultValue": { "Ref": "AWS::NoValue" } } ] } } } ] } }
YAML
AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::LanguageExtensions Mappings: NatGateway: Condition: B: TwoNatGateways C: ThreeNatGateways Resources: Fn::ForEach::NatGatewayAndEIP: - Identifier - - A - B - C - NatGateway${Identifier}: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt - !Sub NatGatewayAttachment${Identifier} - AllocationId SubnetId: !Ref Fn::Sub: PublicSubnet${Identifier} Condition: !FindInMap - NatGateway - Condition - !Ref Identifier - DefaultValue: !Ref AWS::NoValue NatGatewayAttachment${Identifier}: Type: AWS::EC2::EIP Properties: Domain: vpc Condition: !FindInMap - NatGateway - Condition - !Ref Identifier - DefaultValue: !Ref AWS::NoValue
O modelo transformado será equivalente ao modelo a seguir:
AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::LanguageExtensions Resources: NatGatewayA: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt - NatGatewayAttachmentA - AllocationId SubnetId: !Ref PublicSubnetA NatGatewayB: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt - NatGatewayAttachmentB - AllocationId SubnetId: !Ref PublicSubnetB Condition: TwoNatGateways NatGatewayC: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt - NatGatewayAttachmentC - AllocationId SubnetId: !Ref PublicSubnetC Condition: ThreeNatGateways NatGatewayAttachmentA: Type: AWS::EC2::EIP Properties: Domain: vpc NatGatewayAttachmentB: Type: AWS::EC2::EIP Properties: Domain: vpc Condition: TwoNatGateways NatGatewayAttachmentC: Type: AWS::EC2::EIP Properties: Domain: vpc Condition: ThreeNatGateways
Replicar vários recursos usando loops Fn::ForEach
aninhados
Este exemplo usa loops Fn::ForEach
aninhados para mapear três recursos (AWS::EC2::NetworkAcl
, AWS::EC2::Subnet
e AWS::EC2::SubnetNetworkAclAssociation
) entre si.
JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::LanguageExtensions", "Resources": { "VPC": { "Type": "AWS::EC2::VPC", "Properties": { "CidrBlock": "10.0.0.0/16", "EnableDnsSupport": "true", "EnableDnsHostnames": "true" } }, "Fn::ForEach::SubnetResources": [ "Prefix", [ "Transit", "Public" ], { "Nacl${Prefix}Subnet": { "Type": "AWS::EC2::NetworkAcl", "Properties": { "VpcId": { "Ref": "VPC" } } }, "Fn::ForEach::LoopInner": [ "Suffix", [ "A", "B", "C" ], { "${Prefix}Subnet${Suffix}": { "Type": "AWS::EC2::Subnet", "Properties": { "VpcId": { "Ref": "VPC" } } }, "Nacl${Prefix}Subnet${Suffix}Association": { "Type": "AWS::EC2::SubnetNetworkAclAssociation", "Properties": { "SubnetId": { "Ref": { "Fn::Sub": "${Prefix}Subnet${Suffix}" } }, "NetworkAclId": { "Ref": { "Fn::Sub": "Nacl${Prefix}Subnet" } } } } } ] } ] } }
YAML
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Resources: VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: 10.0.0.0/16 EnableDnsSupport: 'true' EnableDnsHostnames: 'true' 'Fn::ForEach::SubnetResources': - Prefix - [Transit, Public] - 'Nacl${Prefix}Subnet': Type: 'AWS::EC2::NetworkAcl' Properties: VpcId: !Ref 'VPC' 'Fn::ForEach::LoopInner': - Suffix - [A, B, C] - '${Prefix}Subnet${Suffix}': Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref 'VPC' 'Nacl${Prefix}Subnet${Suffix}Association': Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref 'Fn::Sub': '${Prefix}Subnet${Suffix}' NetworkAclId: !Ref 'Fn::Sub': 'Nacl${Prefix}Subnet'
O modelo transformado será equivalente ao modelo a seguir:
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Resources: VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: 10.0.0.0/16 EnableDnsSupport: 'true' EnableDnsHostnames: 'true' NaclTransitSubnet: Type: 'AWS::EC2::NetworkAcl' Properties: VpcId: !Ref VPC TransitSubnetA: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC NaclTransitSubnetAAssociation: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref TransitSubnetA NetworkAclId: !Ref NaclTransitSubnet TransitSubnetB: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC NaclTransitSubnetBAssociation: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref TransitSubnetB NetworkAclId: !Ref NaclTransitSubnet TransitSubnetC: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC NaclTransitSubnetCAssociation: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref TransitSubnetC NetworkAclId: !Ref NaclTransitSubnet NaclPublicSubnet: Type: 'AWS::EC2::NetworkAcl' Properties: VpcId: !Ref VPC PublicSubnetA: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC NaclPublicSubnetAAssociation: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref PublicSubnetA NetworkAclId: !Ref NaclPublicSubnet PublicSubnetB: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC NaclPublicSubnetBAssociation: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref PublicSubnetB NetworkAclId: !Ref NaclPublicSubnet PublicSubnetC: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC NaclPublicSubnetCAssociation: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref PublicSubnetC NetworkAclId: !Ref NaclPublicSubnet
Fazer referência a propriedades replicadas para um recurso do Amazon EC2
Este exemplo usa a função intrínseca Fn::ForEach
para referenciar recursos AWS::EC2::Instance
replicados.
JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::LanguageExtensions", "Mappings": { "Instances": { "InstanceType": { "B": "m5.4xlarge", "C": "c5.2xlarge" }, "ImageId": {"A": "ami-id1"} } }, "Resources": { "Fn::ForEach::Instances": [ "Identifier", [ "A", "B", "C" ], { "Instance${Identifier}": { "Type": "AWS::EC2::Instance", "Properties": { "InstanceType": { "Fn::FindInMap": [ "Instances", "InstanceType", {"Ref": "Identifier"}, {"DefaultValue": "m5.xlarge"} ] }, "ImageId": { "Fn::FindInMap": [ "Instances", "ImageId", {"Ref": "Identifier"}, {"DefaultValue": "ami-id-default"} ] } } } } ] }, "Outputs": { "SecondInstanceId": { "Description": "Instance Id for InstanceB", "Value": {"Ref": "InstanceB"} }, "SecondPrivateIp": { "Description": "Private IP for InstanceB", "Value": { "Fn::GetAtt": [ "InstanceB", "PrivateIp" ] } } } }
YAML
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Mappings: Instances: InstanceType: B: m5.4xlarge C: c5.2xlarge ImageId: A: ami-id1 Resources: 'Fn::ForEach::Instances': - Identifier - [A, B, C] - 'Instance${Identifier}': Type: 'AWS::EC2::Instance' Properties: InstanceType: !FindInMap [Instances, InstanceType, !Ref 'Identifier', {DefaultValue: m5.xlarge}] ImageId: !FindInMap [Instances, ImageId, !Ref 'Identifier', {DefaultValue: ami-id-default}] Outputs: SecondInstanceId: Description: Instance Id for InstanceB Value: !Ref 'InstanceB' SecondPrivateIp: Description: Private IP for InstanceB Value: !GetAtt [InstanceB, PrivateIp]
O modelo transformado será equivalente ao modelo a seguir:
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Resources: InstanceA: Type: 'AWS::EC2::Instance' Properties: InstanceType: m5.xlarge ImageId: ami-id1 InstanceB: Type: 'AWS::EC2::Instance' Properties: InstanceType: m5.4xlarge ImageId: ami-id-default InstanceC: Type: 'AWS::EC2::Instance' Properties: InstanceType: c5.2xlarge ImageId: ami-id-default Outputs: SecondInstanceId: Description: Instance Id for InstanceB Value: !Ref InstanceB SecondPrivateIp: Description: Private IP for InstanceB Value: !GetAtt [InstanceB, PrivateIp]
Replicar propriedades de um recurso do Amazon EC2
Este exemplo usa a função intrínseca Fn::ForEach
para repetir algumas propriedades como ImageId
, InstanceType
e AvailabilityZone
para um recurso AWS::EC2::Instance
.
JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::LanguageExtensions", "Mappings": { "InstanceA": { "Properties": { "ImageId": "ami-id1", "InstanceType": "m5.xlarge" } }, "InstanceB": { "Properties": { "ImageId": "ami-id2" } }, "InstanceC": { "Properties": { "ImageId": "ami-id3", "InstanceType": "m5.2xlarge", "AvailabilityZone": "us-east-1a" } } }, "Resources": { "Fn::ForEach::Instances": [ "InstanceLogicalId", [ "InstanceA", "InstanceB", "InstanceC" ], { "${InstanceLogicalId}": { "Type": "AWS::EC2::Instance", "Properties": { "DisableApiTermination": true, "UserData": { "Fn::Base64": { "Fn::Join": [ "", [ "#!/bin/bash\n", "yum update -y\n", "yum install -y httpd.x86_64\n", "systemctl start httpd.service\n", "systemctl enable httpd.service\n", "echo \"Hello World from $(hostname -f)\" > /var/www/html/index.html\n" ] ] } }, "Fn::ForEach::Properties": [ "PropertyName", [ "ImageId", "InstanceType", "AvailabilityZone" ], { "${PropertyName}": { "Fn::FindInMap": [ { "Ref": "InstanceLogicalId" }, "Properties", { "Ref": "PropertyName"}, { "DefaultValue": { "Ref": "AWS::NoValue" } } ] } } ] } } } ] } }
YAML
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Mappings: InstanceA: Properties: ImageId: ami-id1 InstanceType: m5.xlarge InstanceB: Properties: ImageId: ami-id2 InstanceC: Properties: ImageId: ami-id3 InstanceType: m5.2xlarge AvailabilityZone: us-east-1a Resources: 'Fn::ForEach::Instances': - InstanceLogicalId - [InstanceA, InstanceB, InstanceC] - '${InstanceLogicalId}': Type: 'AWS::EC2::Instance' Properties: DisableApiTermination: true UserData: Fn::Base64: !Sub | #!/bin/bash yum update -y yum install -y httpd.x86_64 systemctl start httpd.service systemctl enable httpd.service echo "Hello World from $(hostname -f)" > /var/www/html/index.html 'Fn::ForEach::Properties': - PropertyName - [ImageId, InstanceType, AvailabilityZone] - '${PropertyName}': 'Fn::FindInMap': - Ref: 'InstanceLogicalId' - Properties - Ref: 'PropertyName' - {DefaultValue: !Ref 'AWS::NoValue'}
O modelo transformado será equivalente ao modelo a seguir:
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Resources: InstanceA: Type: 'AWS::EC2::Instance' Properties: DisableApiTermination: true UserData: Fn::Base64: !Sub | #!/bin/bash yum update -y yum install -y httpd.x86_64 systemctl start httpd.service systemctl enable httpd.service echo "Hello World from $(hostname -f)" > /var/www/html/index.html ImageId: ami-id1 InstanceType: m5.xlarge InstanceB: Type: 'AWS::EC2::Instance' Properties: DisableApiTermination: true UserData: Fn::Base64: !Sub | #!/bin/bash yum update -y yum install -y httpd.x86_64 systemctl start httpd.service systemctl enable httpd.service echo "Hello World from $(hostname -f)" > /var/www/html/index.html ImageId: ami-id2 InstanceC: Type: 'AWS::EC2::Instance' Properties: DisableApiTermination: true UserData: Fn::Base64: !Sub | #!/bin/bash yum update -y yum install -y httpd.x86_64 systemctl start httpd.service systemctl enable httpd.service echo "Hello World from $(hostname -f)" > /var/www/html/index.html ImageId: ami-id3 InstanceType: m5.2xlarge AvailabilityZone: us-east-1a
Passar caracteres não alfanuméricos da Collection
para Fn::ForEach
Esse exemplo usa a sintaxe &{}
, que permite que caracteres não alfanuméricos (.
e /
) dos endereços IP sejam passados na Collection
.
JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::LanguageExtensions", "Parameters": { "IpAddresses": { "Type": "CommaDelimitedList", "Default": "10.0.2.0/24,10.0.3.0/24,10.0.4.0/24" } }, "Resources": { "VPC": { "Type": "AWS::EC2::VPC", "Properties": { "CidrBlock": "10.0.0.0/16", "EnableDnsSupport": "true", "EnableDnsHostnames": "true" } }, "Fn::ForEach::Subnets": [ "CIDR", { "Ref": "IpAddresses" }, { "Subnet&{CIDR}": { "Type": "AWS::EC2::Subnet", "Properties": { "VpcId": { "Ref": "VPC" }, "CidrBlock": { "Ref": "CIDR" } } } } ] } }
YAML
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Parameters: IpAddresses: Type: CommaDelimitedList Default: '10.0.2.0/24,10.0.3.0/24,10.0.4.0/24' Resources: VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: 10.0.0.0/16 EnableDnsSupport: 'true' EnableDnsHostnames: 'true' 'Fn::ForEach::Subnets': - CIDR - !Ref IpAddresses - 'Subnet&{CIDR}': Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: !Ref CIDR
O modelo transformado será equivalente ao modelo a seguir:
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::LanguageExtensions' Parameters: IpAddresses: Type: CommaDelimitedList Default: '10.0.2.0/24,10.0.3.0/24,10.0.4.0/24' Resources: VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: 10.0.0.0/16 EnableDnsSupport: 'true' EnableDnsHostnames: 'true' Subnet1002024: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: 10.0.2.0/24 Subnet1003024: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: 10.0.3.0/24 Subnet1004024: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: 10.0.4.0/24