4
votes

I am trying to create a condition based on an optional parameter. The option is whether to run some additional installation from my userData script for an EC2 deployment.

The parameters and conditions look like this:

Parameters: 
  EnvType: 
    Description: Option to install New Relic Infrastructure.
    Default: apm
    Type: String
  AllowedValues: 
    - apm
    - +infra

Then my EC2 Resource with conditional startup scripts

Resources:
  Ec2Instance:
    Type: AWS::EC2::Instance
    Properties:
     InstanceType: t2.micro
     ImageId: ami-9c9443e3  #Amazon Linux AMI in Tokyo
     KeyName: tokyocloudformation
     IamInstanceProfile: 'S3EC2'
     SecurityGroupIds:
         - !Ref myNewSecurityGroup   
     UserData:
        Condition: apmOnly
        Fn::Base64:
          |
            #!/bin/bash
            installstuff
      Condition: addInfrastructureAgent
        Fn::Base64:
          |
           #!/bin/bash
           installstuff
           installsomeotherstuff

The error message I'm getting is: Template validation error: Template format error: Unresolved dependencies [EnvTyp]. Cannot reference resources in the Conditions block of the template

I get what the error is saying I believe, but it doesn't seem to fit with the examples given by AWS.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html . This AWS example clearly uses a !Ref in the Conditions block.

  EnvType: 
    Description: Environment type.
    Default: test
    Type: String
    AllowedValues: 
      - prod
      - test
    ConstraintDescription: must specify prod or test.
  Conditions: 
    CreateProdResources: !Equals [ !Ref EnvType, prod ]

Can someone provide some feedback on how to implement this conditional or why this error message is being thrown for this implementation?

2
You should condition the script not the resource. The resource is identical in each case. Only the script changes. - Rodrigo M
Thanks! I also found where I'd need the following (cfn-hup) to implement conditionally in userData, so that the script runs again on restarts or updates from cfn. Leaving here for posterity. docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/… docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/… - Brad Ellis

2 Answers

5
votes

According to the docs, Conditions should be used at the top level of the resource you want to conditionally create.

Putting a Condition inside the Instance UserData section isn't supported.

To use Conditions in your situation, you'd want separate Resources conditionally created based on the Parameter.

Resources:
  Ec2InstanceAPMOnly:
    Type: AWS::EC2::Instance
    Condition: apmOnly
    Properties:
     InstanceType: t2.micro
     ImageId: ami-9c9443e3  #Amazon Linux AMI in Tokyo
     KeyName: tokyocloudformation
     IamInstanceProfile: 'S3EC2'
     SecurityGroupIds:
         - !Ref myNewSecurityGroup   
     UserData:
        Fn::Base64:
          !Sub |
            #!/bin/bash
            installstuff

  Ec2InstanceWithInfrastructureAgent:
    Type: AWS::EC2::Instance
    Condition: addInfrastructureAgent
    Properties:
     InstanceType: t2.micro
     ImageId: ami-9c9443e3  #Amazon Linux AMI in Tokyo
     KeyName: tokyocloudformation
     IamInstanceProfile: 'S3EC2'
     SecurityGroupIds:
         - !Ref myNewSecurityGroup   
     UserData:
        Fn::Base64:
          !Sub |
            #!/bin/bash
            installstuff
            installsomeotherstuff