This is the 2nd instalment in the series of “old dog learning new cloudformation tricks” ;-)
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
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 is to create an intermediate resource where I can make conditional reference
AWS::EC2::VPCCidrBlock if it exists. In resource metadata it is perfectly fine
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
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.