Conditional Dependency in Cloudformation
This is the 2nd instalment in the series of “old dog learning new cloudformation tricks” ;-)
Problem
Story begins from a VPC template where I wanted to have an option to define secondary CIDR block
so VPC could be expanded or reduced without re-creating the VPC itself. To keep things simple in this
example I have only a VPC with single secondary CIDR block and one subnet. But because subnet may use
addresses from the secondary CIDR block, I must use DependsOn
for AWS::EC2::Subnet
to declare
explicit dependency to AWS::EC2::VPCCidrBlock
ensuring the secondary CIDR block is attached to VPC
before subnet is created.
This would be fine, if the secondary CIDR block would always be part of the stack, but the requirement
was to be able to expand and shrink the VPC on demand, ie. AWS::EC2::VPCCidrBlock
would have to
be a conditional resource. In normal case I would use Fn::If
to disable dependency when seconday
CIDR block is not present.
Subnet:
Type: AWS::EC2::Subnet
DependsOn:
Fn::If:
- VpcCidrSecondaryExists
- Ref: VPCSecondaryCIDR
- Ref: AWS::NoValue
But this will fail template validation because DependsOn
can not contain any functions :-(
Template format error: DependsOn must be a string or list of strings.
Solution
Solution is to create an intermediate resource where I can make conditional reference
to AWS::EC2::VPCCidrBlock
if it exists. In resource metadata it is perfectly fine
to use Fn::If
and reference to CIDR block only if it exists.
VPCReady:
Type: AWS::CloudFormation::WaitConditionHandle
Metadata:
SecondaryCIDRready: !If [ VpcCidrSecondaryExists, !Ref VPCSecondaryCIDR, "" ]
VPCReady
is always created but it makes reference to conditional CIDR block only if
it does exists in the stack. Now it is also safe to make subnet depend on VPCReady
as it is not conditional resource. Problem (almost) solved!
It turns out that if I try to remove CIDR block and update the subnet using the block, update will fail to delete CIRD block as subnet deletion isn’t finished.
Fortunately Cloudformation will retry CIDR block delete and eventually succeed. If you don’t like red error messages, work-a-round is to make the update in 2 steps; first relocate subnet to free CIDR block and then remove CIDR block. Doing a single change at the time is a good practise anyways.