CloudFormation - 使用条件,伪参数和内部函数一起定义单个资源属性

时间:2017-11-19 21:48:12

标签: amazon-web-services yaml amazon-cloudformation autoscaling elastic-load-balancer

我有一个CloudFormation模板,它定义了两个条件。如果我们在us-west-2(支持网络ELB IS )中启动堆栈,则会将CreateNetworkLoadBalancer设置为True。如果我们在sa-east-1(圣保罗,支持Classic ELB)中运行此堆栈,则CreateNetworkLoadBalancer设置为False,{ {1}}是CreateClassicLoadBalancer。 (以下示例)

True

该堆栈稍后定义了两个资源,即Network和Classic ELB,如下所示。它根据区域和条件仅旋转适当的LB.这一切都按预期工作。 (以下示例)

Conditions:
  CreateClassicLoadBalancer: !Equals [ !Ref "AWS::Region", sa-east-1 ]
  CreateNetworkLoadBalancer: !Equals [ !Ref "AWS::Region", us-west-2 ]

通过堆栈更新,我们现在想要添加代码以将现有的Load Balancer(基于该区域配置的Load Balancer)与AutoScaling组相关联。为此,AutoScaling为每个(网络负载均衡器目标组Resources: ###################################################### # Network Load Balancer, Target Group, etc. # NLB NLB: Type: "AWS::ElasticLoadBalancingV2::LoadBalancer" Condition: CreateNetworkLoadBalancer Properties: LoadBalancerAttributes: - Key: deletion_protection.enabled Value: False Name: !Join [ "-", [ !Ref awsTagsNamePrefix, "nlb" ] ] Scheme: internet-facing Subnets: !Ref bastionSubnetList Tags: - Key: Environment Value: !Ref awsTagsEnvironment - Key: Application Value: !Ref awsTagsApplication - Key: Name Value: !Join [ "-", [ !Ref awsTagsNamePrefix, "nlb" ] ] Type: network IpAddressType: ipv4 # target group NLBTargetGroup: Type: "AWS::ElasticLoadBalancingV2::TargetGroup" Condition: CreateNetworkLoadBalancer Properties: HealthCheckIntervalSeconds: 30 HealthCheckPort: 22 HealthCheckProtocol: TCP HealthCheckTimeoutSeconds: 10 HealthyThresholdCount: 3 Name: !Join [ "-", [ !Ref awsTagsNamePrefix, "elb-target-group" ] ] Port: 22 Protocol: TCP Tags: - Key: Environment Value: !Ref awsTagsEnvironment - Key: Application Value: !Ref awsTagsApplication - Key: Name Value: !Join [ "-", [ !Ref awsTagsNamePrefix, "elb-target-group" ] ] TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: 0 UnhealthyThresholdCount: 3 VpcId: !Select [0, !Ref vpcIdList] # Listener NLBListener: Type: AWS::ElasticLoadBalancingV2::Listener Condition: CreateNetworkLoadBalancer Properties: DefaultActions: - TargetGroupArn: !Ref NLBTargetGroup Type: forward LoadBalancerArn: !Ref NLB Port: 22 Protocol: TCP ###################################################### ###################################################### # Classic ELB - for regions that do not yet support a Network LB. # ELB ELB: Type: "AWS::ElasticLoadBalancing::LoadBalancer" Condition: CreateClassicLoadBalancer Properties: Subnets: !Ref bastionSubnetList HealthCheck: HealthyThreshold: '3' Interval: '10' Target: TCP:22 Timeout: '5' UnhealthyThreshold: '3' ConnectionSettings: IdleTimeout: '60' CrossZone: 'true' SecurityGroups: - Ref: BastionELBSG Listeners: - InstancePort: '22' LoadBalancerPort: '22' Protocol: TCP InstanceProtocol: TCP LoadBalancerName: !Join [ "-", [ !Ref awsTagsNamePrefix, "bastion-elb" ] ] Tags: - Key: Environment Value: !Ref awsTagsEnvironment - Key: Application Value: !Ref awsTagsApplication - Key: Name Value: !Join [ "-", [ !Ref awsTagsNamePrefix, "bastion-elb" ] ] 和经典ELB的TargetGroupARNs分别具有属性。我们在LoadBalancerNames中定义两者,并依赖于条件的True / False值,内部函数(AWS::AutoScaling::AutoScalingGroup)和Fn::If伪参数。从理论上讲,下面的代码应该可行。

AWS::NoValue

然而,Yaml的语法/格式不正确 - 我们在运行堆栈时遇到以下错误(属性TargetGroupARNs的值必须是String类型的列表)

将If,条件和NoValue绑定在一起的正确方法是什么,以便单个String的列表(导致!Ref到 NoValue NLB )被赋值为TargetGroupARNs: !If - CreateNetworkLoadBalancer - !Ref NLBTargetGroup - !Ref "AWS::NoValue" LoadBalancerNames: !If - CreateClassicLoadBalancer - !Ref ELB - !Ref "AWS::NoValue" 的值?

TargetGroupARNs

2 个答案:

答案 0 :(得分:2)

我认为您最好在资源上使用conditions创建两个BastionASG资源

BastionASGElb:
  Type: AWS::AutoScaling::AutoScalingGroup
  Condition: CreateClassicLoadBalancer
  Properties:
    AvailabilityZones:
      Fn::GetAZs: !Ref "AWS::Region"
    Cooldown: '0'
    DesiredCapacity: '0'
    HealthCheckGracePeriod: '60'
    HealthCheckType: EC2
    MaxSize: '0'
    MinSize: '0'
    VPCZoneIdentifier: !Ref bastionSubnetList
    LaunchConfigurationName:
      Ref: BastionLC
    Tags:
    - Key: Environment
      Value: !Ref awsTagsEnvironment
      PropagateAtLaunch: true
    - Key: Application
      Value: !Ref awsTagsApplication
      PropagateAtLaunch: true
    - Key: Name
      Value: !Join [ "-", [ !Ref awsTagsNamePrefix, "asg-ec2" ] ]
      PropagateAtLaunch: true
    LoadBalancerNames:
      - !Ref ELB
    TerminationPolicies:
    - OldestInstance

BastionASGAlb:
  Type: AWS::AutoScaling::AutoScalingGroup
  Condition: CreateNetworkLoadBalancer
  Properties:
    AvailabilityZones:
      Fn::GetAZs: !Ref "AWS::Region"
    Cooldown: '0'
    DesiredCapacity: '0'
    HealthCheckGracePeriod: '60'
    HealthCheckType: EC2
    MaxSize: '0'
    MinSize: '0'
    VPCZoneIdentifier: !Ref bastionSubnetList
    LaunchConfigurationName:
      Ref: BastionLC
    Tags:
    - Key: Environment
      Value: !Ref awsTagsEnvironment
      PropagateAtLaunch: true
    - Key: Application
      Value: !Ref awsTagsApplication
      PropagateAtLaunch: true
    - Key: Name
      Value: !Join [ "-", [ !Ref awsTagsNamePrefix, "asg-ec2" ] ]
      PropagateAtLaunch: true
    TargetGroupARNs:  
      - !Ref NLBTargetGroup
    TerminationPolicies:
    - OldestInstance

答案 1 :(得分:1)

在YAML中,您可以使用两个短划线- -来创建列表列表:

Prop:
  - - one
    - two
    - three
  - - red
    - blue

因此,对于绑定到列表属性的!If语句,您将第二个值包装在子列表中:

TargetGroupARNs:
  !If
    - CreateNetworkLoadBalancer

    - - !Ref NLBTargetGroup

    - !Ref "AWS::NoValue"

查看我自己的脚本看起来AWS::NoValue不需要被包装,但如果你在第二个块中有一个不同的!Ref,那么它也需要是一个子列表。