More AWS questions! Ok, so the idea is one master template calls all the nested stacks. With help from here I figured out how to pass parameters from the master to the nested stacks. Now I am trying to figure out how to pass values from nested stacks to nested stacks. I believe this should be done via Exports and Imports, but I don't think I have this quite right. I'm not sure if it's my imports or exports that are wrong.
The error I am getting is:
No export named TestStack1-VpcStackID found. Rollback requested by user.
Master:
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Master template",
"Parameters" : {
"availabilityZone" : {
"Default" : "us-east-1d",
"Description" : "Enter AvailabilityZone.",
"Type" : "String"
},
"VpcCidrBlock" : {
"Default" : "10.0.0.0/16",
"Description" : "VPC CIDR Block.",
"Type" : "String"
},
"PublicSubnetCidrBlock" : {
"Default" : "10.0.0.0/24",
"Description" : "Public subnet CIDR block.",
"Type" : "String"
}
},
"Resources" : {
"VpcStack" : {
"Type" : "AWS::CloudFormation::Stack",
"Properties" : {
"Parameters" : {
"VpcCidrBlock" : {
"Ref" : "VpcCidrBlock"
}
},
"TemplateURL" : "https://s3.amazonaws.com/url/templates/vpcStack.json",
"TimeoutInMinutes" : "5"
}
},
"PublicRouteStack" : {
"Type" : "AWS::CloudFormation::Stack",
"Properties" : {
"Parameters" : {
"PublicSubnetCidrBlock" : {
"Ref" : "PublicSubnetCidrBlock"
},
"VpcStack" : {
"Fn::ImportValue" : {
"Fn::Sub" : "${AWS::StackName}-VpcStackID"
}
}
},
"TemplateURL" : "https://s3.amazonaws.com/url/templates/publicRouteStack.json",
"TimeoutInMinutes" : "5"
}
}
}
}
VpcStack (Nested - I don't think I'm outputting right):
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "VPC template",
"Parameters" : {
"VpcCidrBlock" : {
"Description" : "Vpc CIDR Block.",
"Type" : "String"
}
},
"Resources" : {
"VpcStack" : {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"EnableDnsSupport" : "true",
"EnableDnsHostnames" : "true",
"CidrBlock" : {
"Ref" : "VpcCidrBlock"
},
"Tags" : [
{
"Key" : "Application",
"Value" : {
"Ref" : "AWS::StackName"
}
}
]
}
}
},
"Outputs" : {
"VpcStack" : {
"Description" : "VPC Stack ID.",
"Value" : {
"Ref" : "VpcStack"
},
"Export" : {
"Name" : {
"Fn::Sub" : "${AWS::StackName}-VpcStackID"
}
}
}
}
}
PublicStubnetStack (I think this is where it is failing):
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Public Subnet Stack",
"Parameters" : {
"PublicSubnetCidrBlock" : {
"Default" : "10.0.0.0/24",
"Description" : "Public subnet CIDR block.",
"Type" : "String"
},
"VpcStack" : {
"Description" : "VPC Stack.",
"Type" : "String"
}
},
"Resources" : {
"PublicSubnet" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"VpcId" : {
"Ref" : "VpcStack"
},
"CidrBlock" : {
"Ref" : "PublicSubnetCidrBlock"
},
"Tags" : [
{
"Key" : "Application",
"Value" : {
"Ref" : "AWS::StackName"
}
},
{
" Key" : "Network",
"Value" : "Public"
}
]
}
}
},
"Outputs" : {
"PublicSubnet" : {
"Description" : "Public Subnet ID.",
"Value" : {
"Ref" : "PublicSubnet"
},
"Export" : {
"Name" : {
"Fn::Sub" : "${AWS::StackName}-PublicSubnetID"
}
}
}
}
}
Sorry to be posting so many, I am very new to AWS, and am trying to pick it up quickly.
The Problem
Your problem is that you are exporting the value as
"Export" : {
"Name" : {
"Fn::Sub" : "${AWS::StackName}-VpcStackID"
}
}
You are using the ${AWS::StackName}
variable which will substitute the current stack name into your export variable name. Note that this is the stack name of your nested stack.
Whereas, in your wrapper template, you are attempting to import the value as:
"Fn::ImportValue" : {
"Fn::Sub" : "${AWS::StackName}-VpcStackID"
}
Again, you are substituting the variable ${AWS::StackName}
for the current stack, which in this case is your wrapper stack.
Note that when you use nested stacks, you are actually creating a new stack, so the stack names change depending on which template you are in.
The Resolution
Do not use import/export for your variables.
In your nested templates, drop the Export
element from your outputs. You don't need them. Simply use stack parameters to pass values from your wrapper stack to nested stacks, and use stack outputs to pass values back up from nested stacks to wrapper stacks.
In your wrapper stack, use the output from VpcStack
like this:
"PublicRouteStack" : {
"Type" : "AWS::CloudFormation::Stack",
"Properties" : {
"Parameters" : {
"PublicSubnetCidrBlock" : {
"Ref" : "PublicSubnetCidrBlock"
},
"VpcStack" : {
"Fn::GetAtt" : [ "VpcStack", "Outputs.VpcStack" ]
}
},
"TemplateURL" : "https://s3.amazonaws.com/url/templates/publicRouteStack.json",
"TimeoutInMinutes" : "5"
}
}
Note that in this case, I am using the output named VpcStack
from your VpcStack
nested stack via the Fn::GetAtt
function.
PS. You should change some of your names simply for clarity. Try to avoid reusing the same name all over the place. It helps make things clear.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With