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

Пожалуйста, предложите мне более подробную информацию, если потребуется (atleast stackoverflow хочет получить больше деталей, но не указывая какие-либо: -P)

Ответ 1

Вы можете сделать это, используя Fn:GetAtt, завернутый в условный Fn:If. Использование Fn: GetAtt подразумевает зависимость, поэтому CloudFormation будет автоматически ждать, когда она достигнет этой функции, так же, как если бы вы использовали DependsOn.

Пример

В приведенном ниже фрагменте кода показано это путем условного извлечения имени вложенного стека, который еще не создан, но делает это только в том случае, если для условия UseNestedStack установлено значение true. Если UseNestedStack является ложным, он не будет ждать и вместо этого получит локальное имя переменной.

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

Как мне это узнать? (Другой пример)

К сожалению, официальная официальная документация официально не указана, но именно AWS сказал мне сделать это таким образом, и в их примерах кода вы можете видеть, что при выполнении заказов они используют Fn: GetAtt. Я пробовал это много раз, и он работает каждый раз. Попробуйте сами на простой стек. Вот еще несколько доказательств из примера AWS лямбда, который я настраивал и использовал сам. Стек ниже не может работать, если функция AMI создается после информации AMI ресурса, AMI Info требует вывода функции AMI, поэтому AWS скопировал их вместе, используя Fn: GetAtt. Чтобы увидеть этот прокрутки в нижней части экрана и посмотрите на ресурс AMIInfo, и вы увидите, что он ссылается на AMIFunction через fn: Gett. 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" }
  }
}

Ответ 2

Я борюсь с тем же. Ошибка:

Ошибка клиента (ValidationError) произошла при вызове Работа с ValidateTemplate: ошибка формата шаблона: DependsOn должен быть строка или список строк.

Кажется невозможным поставить условие в DependsOn.

Я начал изучать другие способы выразить это. Возможно, размещение зависимого кода в 2 разных дочерних шаблона. Определите условие извне и передайте соответствующее вложенное имя шаблона в параметр родительского шаблона. Таким образом, DependsOn видит параметр I, который проходит в качестве зависимого шаблона.

Похоже на чересстрочную логику.

Должен быть лучший способ.

Ответ 3

В вашем шаблоне вам не нужно добавлять атрибут DependsOn к вашему ресурсу MyStaticDistribution, поскольку у вас уже есть ссылка на ресурс StaticBucket.

Это описано в разделе Задание зависимостей в блоге Оптимизировать AWS CloudFormation Templates: 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.