I've made a nested cloudformation parent template that then references 4 child templates. When I try to launch the stack via the CLI command aws cloudformation create-stack...
I get the error:
An error occurred (ValidationError) when calling the CreateStack
operation: Template error: instance of Fn::GetAtt references undefined
resource BatchScatterGatherSubmissionActivity
This is because I have a child template called StepFunctionResourcesStack that contains the BatchScatterGatherSubmissionActivity
and then another child template EC2InstanceResourcesStack that references it. I made sure to add a DependsOn
clause for the latter child template, but I still get the error.
Here is the StepFunctionResourcesStack :
AWSTemplateFormatVersion: '2010-09-09'
Description: step functions resources stack.
Parameters:
StackUID:
Type: String
Resources:
StatesExecutionRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- !Sub states.${AWS::Region}.amazonaws.com
Action: "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: StatesExecutionPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "lambda:InvokeFunction"
Resource: "*"
MyStateMachine:
Type: "AWS::StepFunctions::StateMachine"
Properties:
#
# The StateMachine definition is substituted in with Jinja2
#
DefinitionString: !Sub
- |
{{ machine_json | indent(10) }}
- {% for item in machine_args -%}
{{ item }}
{% endfor %}
RoleArn: !GetAtt [ StatesExecutionRole, Arn ]
# several of these:
BatchScatterGatherSubmissionActivity:
Type: "AWS::StepFunctions::Activity"
Properties:
Name:
Fn::Join: [ "-", [ "BatchScatterGatherSubmissionActivity", Ref: StackUID] ]
BatchScatterGatherPollingActivity:
Type: "AWS::StepFunctions::Activity"
Properties:
Name:
Fn::Join: [ "-", [ "BatchScatterGatherPollingActivity", Ref: StackUID] ]
BatchGatherActivity:
Type: "AWS::StepFunctions::Activity"
Properties:
Name:
Fn::Join: [ "-", [ "BatchGatherActivity", Ref: StackUID] ]
BatchTriodenovoActivity:
Type: "AWS::StepFunctions::Activity"
Properties:
Name:
Fn::Join: [ "-", [ "BatchTriodenovoActivity", Ref: StackUID] ]
BatchHandoffActivity:
Type: "AWS::StepFunctions::Activity"
Properties:
Name:
Fn::Join: [ "-", [ "BatchHandoffActivity", Ref: StackUID] ]
Outputs:
# These get used in the instance_resources child stack.
BatchScatterGatherSubmissionActivity:
Value: !Ref BatchScatterGatherSubmissionActivity
BatchScatterGatherPollingActivity:
Value: !Ref BatchScatterGatherPollingActivity
BatchGatherActivity:
Value: !Ref BatchGatherActivity
BatchTriodenovoActivity:
Value: !Ref BatchTriodenovoActivity
BatchHandoffActivity:
Value: !Ref BatchHandoffActivity
And here is the relevant part of the parent (nested) template where the above outputs are passed into the EC2InstanceResourcesStack:
StepFunctionResourcesStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
StackUID:
Ref: StackUID
TemplateURL: https://s3.amazonaws.com/CFNTemplate/step_functions_resources.stack.yaml
Timeout: "100"
EC2InstanceResourcesStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
BatchScatterGatherSubmissionActivity:
Fn::GetAtt: [ "BatchScatterGatherSubmissionActivity", "Outputs.StepFunctionResourcesStack" ]
BatchScatterGatherPollingActivity:
Fn::GetAtt: [ "BatchScatterGatherPollingActivity", "Outputs.StepFunctionResourcesStack" ]
BatchGatherActivity:
Fn::GetAtt: [ "BatchGatherActivity", "Outputs.StepFunctionResourcesStack" ]
BatchTriodenovoActivity:
Fn::GetAtt: [ "BatchTriodenovoActivity", "Outputs.StepFunctionResourcesStack" ]
BatchHandoffActivity:
Fn::GetAtt: [ "BatchHandoffActivity", "Outputs.StepFunctionResourcesStack" ]
Subnet: !Ref Subnet
GPCESSHKeyPair: !Ref GPCESSHKeyPair
GPCESubnetAZ1: !Ref GPCESubnetAZ1
ActivityAndHandoffAnsibleBucketName: !Ref ActivityAndHandoffAnsibleBucketName
ActivityAndHandoffAnsibleKeyName: !Ref ActivityAndHandoffAnsibleKeyName
ActivityAndHandoffDaemonBucketName: !Ref ActivityAndHandoffDaemonBucketName
ActivityAndHandoffDaemonKeyName: !Ref ActivityAndHandoffDaemonKeyName
ActivityAndHandoffDaemonRequirementsBucketName: !Ref ActivityAndHandoffDaemonRequirementsBucketName
ActivityAndHandoffDaemonRequirementsKeyName: !Ref ActivityAndHandoffDaemonRequirementsKeyName
Rkstr8PkgBucketName: !Ref Rkstr8PkgBucketName
Rkstr8PkgKeyName: !Ref Rkstr8PkgKeyName
TemplateURL: https://s3.amazonaws.com/CFNTemplate/instance_resources.stack.yaml
Timeout: "100"
DependsOn: StepFunctionResourcesStack
For my method of exporting the parameters from the child and passing them to another via the parent template, I followed the approach provided in the answer here: AWS CloudFormation: Passing Values between Nested Stacks
You cannot directly reference resources (via Ref
) from one template in another template, even when they are parent-child or sibling templates. The resources are stack specific unless they are explicitly exported via the Output
section.
So you have 2 options:
Option 1: Export the value(s) you care about for BatchScatterGatherSubmissionActivity
from the child template 1 via the Output
section, then import those values in child template 2.
For example:
In the "source" template:
"Outputs" : {
"MyValue" : {
"Value" : {
"Ref" : "BatchScatterGatherSubmissionActivity"
},
"Export" : {
"Name" : "MyExportedValue"
}
}
}
then import the value in your "consuming" template:
{ "Fn::ImportValue" : "MyExportedValue" }
More information: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-exports.html
One drawback is that you cannot "DependsOn". Also, quite literally child template 2 depends on child template 1.
Option 2: Output the value(s) you care about for BatchScatterGatherSubmissionActivity
out from the child template (ie. up to the parent), then pass those values from the parent down to the other child.
So in child template 1, you would output the value from the child stack:
"Outputs" : {
"MyValue" : {
"Value" : {
"Ref" : "BatchScatterGatherSubmissionActivity"
}
}
}
In child template 2, you would add a parameter to the template via the "Parameters" section, and then reference that parameter.
"Parameters" : {
"MyParam" : {
"Type" : "String",
"Description" : "The value from elsewhere"
}
}
then
{ "Ref" : "MyParam" }
Finally, hook the 2 child stacks together in the parent by passing the output of child template 1 into the parameter of child template 2:
"ChildStack2": {
"Type" : "AWS::CloudFormation::Stack",
"Properties" : {
"Parameters" : {
"MyParam" : { "Fn::GetAtt" : "Outputs.MyValue" }
}
}
}
In this case, child stack 2 won't be created until child stack 1 is ready and outputs it's values, so there's an implied "DependsOn". But in this case, child template 2 does not depend on child template 1. Instead, it depends on anything that fulfills it's input parameter (which can be a parent stack, or something else).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.