title: CloudFormation - Using Conditions, Pseudo Parameters, and Intrinsic Functions Together to define a Single Resource Property
body: <p>I have a CloudFormation template that has two conditions defined. If we're launching the stack in us-west-2 (where the Network ELB <strong>IS</strong> supported), then it sets <code>CreateNetworkLoadBalancer</code> to True. If we're running this stack in sa-east-1 (Sao Paulo, where <strong>only</strong> the Classic ELB is supported), then <code>CreateNetworkLoadBalancer</code> is set to <code>False</code>, and <code>CreateClassicLoadBalancer</code> is <code>True</code>. (Example below)</p>
  
  <pre><code>Conditions:
    CreateClassicLoadBalancer: !Equals [ !Ref "AWS::Region", sa-east-1 ]
    CreateNetworkLoadBalancer: !Equals [ !Ref "AWS::Region", us-west-2 ]
  </code></pre>
  
  <p>The stack later defines two resources, a Network and a Classic ELB, as shown below. It spins up only the the appropriate LB, based on the region and the conditions. This all works as expected. (Example below)</p>
  
  <pre><code>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" ] ]
  </code></pre>
  
  <p>Via a Stack Update, we now want to add code to associate the existing Load Balancer (the one that was provisioned based on the region), to an AutoScaling group. To do this, AutoScaling has separate Properties for each (<code>TargetGroupARNs</code> for Network LoadBalancer Target Groups, and <code>LoadBalancerNames</code> for Classic ELBs). We're defining both in <code>AWS::AutoScaling::AutoScalingGroup</code>, and relying on the True/False value of the condition, an intrinsic function (<code>Fn::If</code>), and the <code>AWS::NoValue</code> pseudo parameter. In theory the below code should work.</p>
  
  <pre><code>TargetGroupARNs:
          !If
            - CreateNetworkLoadBalancer
            - !Ref NLBTargetGroup
            - !Ref "AWS::NoValue"
        LoadBalancerNames:
          !If
            - CreateClassicLoadBalancer
            - !Ref ELB
            - !Ref "AWS::NoValue"
  </code></pre>
  
  <p>However the syntax/format of the Yaml just isn't correct - We are getting the following error when running the stack <strong>(Value of property TargetGroupARNs must be of type List of String)</strong>. </p>
  
  <p>What is the proper way to tie the If, the conditions, and NoValue together so that a List of a single String (resulting in either a !Ref to <strong>NoValue</strong> or <strong>NLB</strong>) is assigned to the value of <code>TargetGroupARNs</code>? </p>
  
  <pre><code>BastionASG:
      Type: AWS::AutoScaling::AutoScalingGroup
      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:
          !If
            - CreateNetworkLoadBalancer
            - !Ref NLBTargetGroup
            - !Ref "AWS::NoValue"
        LoadBalancerNames:
          !If
            - CreateClassicLoadBalancer
            - !Ref ELB
            - !Ref "AWS::NoValue"
        TerminationPolicies:
        - OldestInstance
  </code></pre>