web-dev-qa-db-ja.com

CloudFormation、DependsOnに条件を適用

CDNをS3バケットに依存させる必要があります。ただし、新しいバケットを作成するのではなく、既存のバケットを使用するようにします。

これが私が試しているサンプルコードです:

"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" ] ] },
        ""
      ]
    }]
  }
}

必要に応じて、詳細を教えてください(少なくとも、stackoverflowでは詳細が必要ですが、-Pは指定していません)。

18

これを行うには、条件付きFn:GetAttでラップされたFn:Ifを使用します。 Fn:GetAttを使用すると、依存関係が暗黙指定されます。したがって、DeformsOnを使用している場合と同様に、CloudFormationは関数に到達すると自動的に待機します。

以下のコードスニペットは、まだ作成されていないネストされたスタックの名前を条件付きで取得することによってこれを示していますが、条件UseNestedStackがtrueに設定されている場合にのみ取得されます。 UseNestedStackがfalseの場合、待機せず、代わりにローカル変数名を取得します。

{
"Fn::If": ["UseNestedStack", {
    "Fn::GetAtt": ["NestedStack", "Outputs.Name"]
}, {
    "Ref": "LocalName"
}]

どうやってこれを知るのですか?(別の例)

残念ながら、これを公式に述べた公式のドキュメントはありませんが、このようにするように私に言ったのはAWSでした。彼らのコード例では、注文が重要なときにFn:GetAttを使用していることがわかります。私はこれを何度も試しましたが、いつでもうまくいきます。簡単なスタックで試してみてください。これは、私が微調整して自分で使用したAWSラムダの例からのいくつかの疑似証明です。以下のスタックは、リソースAMI情報の後にAMI関数が作成された場合は機能しない可能性があります。AMI情報はAMI関数の出力を必要とするため、AWSはFn:GetAttを使用してそれらをチェーンしました。このスクロールを一番下までスクロールしてリソースAMIInfoを見ると、fn:Gettを介してAMIFunctionを参照していることがわかります。 CloudFormationはこれを確認し、AMIFunctionに戻って最初に作成します。

"AMIInfoFunction": {
  "DependsOn":"SourceStack",
  "Type": "AWS::Lambda::Function",
  "Properties": {
    "Code": {
      "S3Bucket": { "Ref": "DeploymentBucket" },
      "S3Key": {"Fn::Join": [
        "",
        [
          {
            "Ref": "ApplicationName"
          },
          "/amilookup.Zip"
        ]
      ]}
    },
    "Handler": "amilookup.handler",
    "Runtime": "nodejs",
    "Timeout": "30",
    "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] },
    "VpcConfig": {
      "SecurityGroupIds": [ {"Ref": "InstanceSecurityGroup"}],
      "SubnetIds": [ {"Ref":"PrivateSubnetA"},{"Ref":"PrivateSubnetB"} ]
    }
  }
},
"AMIInfo": {
  "Type": "Custom::AMIInfo",
  "Properties": {
    "ServiceToken": { "Fn::GetAtt" : ["AMIInfoFunction", "Arn"] },
    "StackName": { "Ref":"SourceStack" }
  }
}
10
Usman Mutawakil

テンプレートでは、StaticBucketリソースへの参照が既にあるため、MyStaticDistributionリソースにDependsOn属性を追加する必要はありません。

これは、 Optimize AWS CloudFormation Templates blog post Specifying Dependencies セクションに記載されています: https://aws.Amazon .com/blogs/devops/optimize-aws-cloudformation-templates /

When you need CloudFormation to wait to provision one resource until another one has been provisioned, you can use the DependsOn attribute.

You can also introduce references between elements by using either the { "Ref": "MyResource" } or the { "Fn::GetAtt" : [ "MyResource" , "MyAttribute" ] } functions. When you use one of these functions, CloudFormation behaves as if you’ve added a DependsOn attribute to the resource.

3
ali

Yamlユーザーの場合は、次も使用できます。

Conditions:
  CreateConfigRecorder: !Equals [ !Ref ConfigRecorderExists, 'false' ]

Resource:
#my 1st AWS Resource
  ConfigRecorder: 
    Condition: CreateConfigRecorder
    Type: AWS::Config::ConfigurationRecorder
    *more codes below*

#added, since DependsOn: !If is not possible, trigger by WaitCondition if CreateConfigRecorder is true
#Hacks: https://garbe.io/blog/2017/07/17/cloudformation-hacks/
  ConfigRecorderWaitHandle: 
    Condition: CreateConfigRecorder
    DependsOn: ConfigRecorder
    Type: "AWS::CloudFormation::WaitConditionHandle"
#added, since DependsOn: !If is not possible, trigger by WaitCondition if CreateConfigRecorder is false
  WaitHandle: 
    Type: "AWS::CloudFormation::WaitConditionHandle"
#added, since DependsOn: !If is not possible
  WaitCondition: 
    Type: "AWS::CloudFormation::WaitCondition"
    Properties: 
      Handle: !If [CreateConfigRecorder, !Ref ConfigRecorderWaitHandle, !Ref WaitHandle]
      Timeout: "1"
      Count: 0
#my 2nd AWS Resource that requires DependsOn Attribute
  AWSConfigRule:
    Type: AWS::Config::ConfigRule
    DependsOn: WaitCondition #added, since DependsOn: !If is not possible
    *more codes below*

基本的に、CFNを実行する前に、1番目のリソースが存在しない場合、2番目のリソースにはDependsOn属性しかありません。私はこれを手に入れました: https://garbe.io/blog/2017/07/17/cloudformation-hacks/

1
Cj Medina

私は同じことを戦っています。エラーは:

ValidateTemplate操作の呼び出し時にクライアントエラー(ValidationError)が発生しました:テンプレート形式エラー:DependsOnは文字列または文字列のリストでなければなりません。

DependsOn内に条件を置くことは可能ではないようです。

それを表現する他の方法を探し始めました。多分依存するコードを2つの異なる子テンプレートに配置します。条件を外部で検出し、適切なネストされたテンプレート名を親テンプレートパラメータに渡します。したがって、DependsOnは、依存するテンプレートとして渡したパラメーターを参照します。

過度に歪んだロジックのようです。

より良い方法でなければなりません。

0
Bruce Edge