The task that I need to do is make CDN depend on a S3 bucket. But we want to make it use the existing bucket rather than creating a new one.
Here is the sample code that I am trying:
"Parameters" : {
"UseExistingBucket" : {
"Description" : "Yes/No",
"Default" : "yes",
"Type" : "String",
"AllowedValues" : [ "yes", "no" ]
}
},
"Conditions" : {
"CreateS3Resources" : {"Fn::Equals" : [{"Ref" : "UseExistingBucket"}, "no"]}
},
"Resources" : {
"StaticBucket" : {
"Type" : "AWS::S3::Bucket",
"Condition" : "CreateS3Resources",
"Properties" : {
"BucketName" : { "Fn::Join": [ "-", [ "app", { "Ref": "EnvType" }, "static" ] ] }
},
"DeletionPolicy": "Retain"
},
"MyStaticDistribution": {
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"Origins": [
{
"DomainName": {
"Fn::If" : [
"CreateS3Resources",
{ "Fn::Join": [ "-", [ "app", { "Ref": "EnvType" }, "static" ] ] },
{"Fn::GetAtt": [ "StaticBucket", "DomainName" ] }
]
},
"Id": "S3Origin",
}
]
}
},
"DependsOn": [{
"Fn::If" : [
"CreateS3Resources",
{ "Fn::Join": [ "-", [ "app", { "Ref": "EnvType" }, "static" ] ] },
""
]
}]
}
}
Please suggest to me any more details, if they are required (atleast stackoverflow does wants more details, but I have not specified any :-P)
You can do this by using Fn:GetAtt
wrapped in a conditional Fn:If
. Using Fn:GetAtt
implies a dependency, so CloudFormation will automatically wait once it reaches that function, the same as if you were using a DependsOn
.
Example
The code snippet below shows this by conditionally retrieving the name of a nested stack that has not yet been created but only does so if the condition UseNestedStack is set to true. If UseNestedStack is false it will not wait and instead retrieve a local variable name.
{
"Fn::If": ["UseNestedStack", {
"Fn::GetAtt": ["NestedStack", "Outputs.Name"]
}, {
"Ref": "LocalName"
}]
How Do I know This? (Another Example)
Unfortunately there is no official documentation officially stating this but it was AWS that told me to do it this way and in their code examples you can see that when order matters they use Fn:GetAtt. I've tried this numerous times and it works every time. Try it yourself on a simple stack. Here is some more pseudo proof from an AWS lambda example that I tweaked and have used myself. The stack below could not possibly work if the AMI function is created after the resource AMI info, AMI Info needs output of the AMI function, so AWS has chained them together using Fn:GetAtt
. To see this scroll to the bottom and look at the resource AMIInfo and you will see it references AMIFunction
via fn:Gett
. CloudFormation sees this and goes back to AMIFunction
to create it first.
AMIInfoFunction:
DependsOn: SourceStack
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref DeploymentBucket
S3Key: !Join
- ''
- - !Ref ApplicationName
- /amilookup.zip
Handler: amilookup.handler
Runtime: nodejs
Timeout: 30
Role: !GetAtt LambdaExecutionRole.Arn
VpcConfig:
SecurityGroupIds:
- !Ref 'InstanceSecurityGroup'
SubnetIds:
- !Ref PrivateSubnetA
- !Ref PrivateSubnetB
AMIInfo:
Type: Custom::AMIInfo
Properties:
ServiceToken: !GetAtt AMIInfoFunction.Arn
StackName: !Ref SourceStack
Update: This is now documented (Fn::GetAtt
) in the documentation for dependent stacks. Thank you to idoimaging in the comments for pointing that out. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html