【问题标题】:Cloudformation nested stack template ValidationError for child-to-child parameter子到子参数的 Cloudformation 嵌套堆栈模板 ValidationError
【发布时间】:2018-08-17 09:43:39
【问题描述】:

我制作了一个嵌套的 cloudformation 父模板,然后引用 4 个子模板。当我尝试通过 CLI 命令aws cloudformation create-stack... 启动堆栈时,出现错误:

An error occurred (ValidationError) when calling the CreateStack 
operation: Template error: instance of Fn::GetAtt references undefined 
resource BatchScatterGatherSubmissionActivity

这是因为我有一个名为 StepFunctionResourcesStack 的子模板,其中包含 BatchScatterGatherSubmissionActivity,然后是另一个引用它的子模板 EC2InstanceResourcesStack。我确保为后一个子模板添加了 DependsOn 子句,但我仍然收到错误消息。

这里是 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

这里是父(嵌套)模板的相关部分,上面的输出被传递到 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

对于我从子级导出参数并通过父模板将它们传递给另一个的方法,我遵循此处答案中提供的方法:AWS CloudFormation: Passing Values between Nested Stacks

【问题讨论】:

    标签: amazon-web-services nested stack amazon-cloudformation


    【解决方案1】:

    您不能直接从另一个模板中的一个模板引用资源(通过Ref),即使它们是父子模板或兄弟模板。这些资源是特定于堆栈的,除非它们通过Output 部分显式导出。

    所以你有两个选择:

    选项 1:通过 Output 部分从子模板 1 中导出您关心的 BatchScatterGatherSubmissionActivity 值,然后将这些值导入子模板 2。

    例如:

    在“源”模板中:

    "Outputs" : {
      "MyValue" : {
        "Value" : {
          "Ref" : "BatchScatterGatherSubmissionActivity"
        },
        "Export" : {
          "Name" : "MyExportedValue"
        }
      }
    }
    

    然后在您的“消费”模板中导入值:

    { "Fn::ImportValue" : "MyExportedValue" }
    

    更多信息:https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-exports.html

    一个缺点是您不能“DependsOn”。此外,从字面上看,子模板 2 依赖于子模板 1。

    选项 2: 从子模板中输出您关心的 BatchScatterGatherSubmissionActivity 值(即到父模板),然后将这些值从父模板传递到另一个孩子。

    所以在子模板 1 中,您将从子堆栈中输出值:

    "Outputs" : {
      "MyValue" : {
        "Value" : {
          "Ref" : "BatchScatterGatherSubmissionActivity"
        }
      }
    }
    

    在子模板 2 中,您可以通过“参数”部分向模板添加参数,然后引用该参数。

    "Parameters" : {
      "MyParam" : {
        "Type" : "String",
        "Description" : "The value from elsewhere"
      }
    }
    

    然后

    { "Ref" : "MyParam" }
    

    最后,通过将子模板 1 的输出传递到子模板 2 的参数中,将 2 个子堆栈在父级中挂钩:

    "ChildStack2": {
      "Type" : "AWS::CloudFormation::Stack",
      "Properties" : {
        "Parameters" : {
          "MyParam" : { "Fn::GetAtt" : "Outputs.MyValue" }
        }
      }
    }
    

    在这种情况下,在子堆栈 1 准备好并输出它的值之前,不会创建子堆栈 2,因此有一个隐含的“DependsOn”。但在这种情况下,子模板 2 不依赖于子模板 1。相反,它依赖于任何满足其输入参数的东西(可以是父堆栈或其他东西)。

    【讨论】:

    • 感谢您的反馈!选项 2 本质上不是我已经做过的吗(从您对另一篇文章的回答中遵循了您的技术)?
    • 我明白你现在做了什么。在EC2InstanceResourcesStack 中,您的Fn::GetAtt 是倒退的。第一个参数是堆栈,第二个是Outputs.OutputName...你已经在你的代码 sn-p 中颠倒了它。
    • 很棒的答案!这有助于阐明输出在模板中的工作方式。
    猜你喜欢
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    • 2017-11-25
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多