r/aws•
tevert

Cloudformation Conditionals - how to DRY?

technical question

This seems like a larger structural problem in cloudformation which maybe doesn't have an answer, but I thought I'd check and see if anyone's found a better way to do this.

As a simple example, consider a template with a load balancer that has a target group with two EC2 instances behind it. Now, let's say I only want two instances sometimes, so I put a Conditional on one instance.

The rub is that now I need to copy-paste the entire chain of load balancer resources and tweak the copy to only have one backend. Then I have to apply conditionals to both sets of load balancer config so that only one set gets created.

This is a ton of copy-pasted code and it's really bad for reliability. The intuitive way this should work is just doing some kind of !If on the target group to either have one or two instances, but it looks like Cloudformation only supports "If" in the form of Conditionals on resources.

Is there a better way?

Posted Sep 20, 2019, 9:14 PM UTC

717
otsu-swe•

I'm not sure I understand your question, but if you want to build logic into a template Cloudformation isn't really the tool for the job since it's primary function is to be declarative.

If you want evaluative IaC I'd suggest you either look into Terraform or the CDK, which supports evaluation. If you're heavily invested in Cloudformation perhaps CDK is preferable.

https://docs.aws.amazon.com/cdk/latest/guide/constructs.html

https://blog.gruntwork.io/terraform-up-running-2nd-edition-early-release-is-now-available-b104fc29783f#da95

6
tevertOP•

Yeah, Terraform I've used in the past pretty well. We're very heavy into CF at this point though. The CDK stuff looks interesting. I think that's still too big of a change for what I'd consider a small problem, but I'll keep it in mind.

1
ricksebak•

Troposphere may be of interest to you. You can use the full power of python and get loops, if-thens, etc. And let it spit out a static JSON file which you then deploy to CFN.

3
tevertOP•

That's an interesting option, thanks!

1
myroon5•

Jinja is another option for repetitive CloudFormation templates. You will need to render the Jinja template before passing it to CloudFormation, as CloudFormation itself cannot currently process Jinja templates.

5
thatothermitch•

Are you properly using intinsic functions and pseudo parameters, particularly !if and Aws::NoValue? These won't entirely save you, but should pretty significantly reduce duplication.

4
tevertOP•

Hm, that's a good suggestion, !If with a NoValue looks like a possible solution to my problem

3
opalelement•

This is the correct way to do it if you want to use CFTs.

Conditionals in !If blocks can return AWS::NoValue to make it like that property or list element doesn't exist.

For example (typed on my phone so this is meant as a guide and probably won't work as-is):

Resources:
    # Instance1 is always made
    Instance1:
        Type: AWS::EC2::Instance
        Properties:
            ...

    # Instance2 creation is conditional
    Instance2:
        Type: AWS::EC2::Instance
        Condition: shouldMakeTwo
        Properties:
            ...

    TargetGroup:
        Type: AWS::ElasticLoadBalancingV2::TargetGroup
        Properties:
            Targets:
                - Id: !Ref Instance1
                - !If shouldMakeTwo
                    - !Ref Instance2
                    - !Ref AWS::NoValue

If shouldUseTwo is true, you get a second instance and it gets registered to the Target Group. If the condition is false, you don't create the instance, and the AWS::NoValue being returned essentially makes it so that second list item doesn't exist.

2
tevertOP•

Nice, yeah, that's what I was thinking. Thanks a bunch!

2
Singularity42•

You can do it somewhat with nested templates i.e. nest the same template multiple times with different parameters.

I would suggest you might be outgrowing cloudformation though if you are asking these questions.

You may want to consider troposphere if you can't do terraform. From what I remember it generates cloudformation so it might be easier to transition to.

2
ChiXiDigamma•

What about macros? I made an article about that on medium, I could send it to you.

1
tevertOP•

By macros are you thinking some kind of preprocessor syntax? I've used that with Terraform actually. I wouldn't mind seeing what you've done, though I'm trying to see if there's a correct "AWS Way" to do this

1
apitillidie•

Are you not describing an Auto Scale Group?

1
tevertOP•

:) can't use one of those, because of other constraints. That would definitely also be an option normally though

1
gcavalcante8808•

We just changed our yaml walls into jsonnet files and the process of changing or at least read cf became easier. For conditionals it's is the same.

Another option is to try aws cdk but it is a typescript lib tough.

1
Tranceash•

terragrunt + terraform || aws cdk

1