如何检查CloudFormation脚本中是否已存在特定资源

时间:2015-01-23 02:37:46

标签: amazon-web-services automation conditional-statements amazon-cloudformation

我正在使用cloudformation来创建一个包含自动调整的ec2实例和S3存储桶的堆栈。对于S3存储桶,我将DeletionPolicy设置为Retain,工作正常,直到我想再次重新运行我的cloudformation脚本。由于在之前的运行中,脚本创建了S3存储桶,因此在后续运行中失败,说我的S3存储桶已经存在。当然也没有创建其他资源。我的问题是如何检查我的S3存储桶是否首先存在于cloudformation脚本中,如果存在,则跳过创建该资源。我已经查看了AWS中的条件,但它似乎都是基于参数的,我还没有找到一个从现有资源中检查的函数。

6 个答案:

答案 0 :(得分:22)

除非您使用显式检查动态创建模板,否则没有明显的方法可以执行此操作。从同一模板创建的堆栈是独立的实体,如果您创建一个包含存储桶的堆栈,请在保留存储桶的同时删除堆栈,然后创建一个新堆栈(即使是一个具有相同名称的堆栈),这之间没有连接新堆栈和存储桶作为上一个堆栈的一部分创建。

如果要对多个堆栈使用相同的S3存储桶(即使一次只存在其中一个存储桶),该存储桶并不真正属于堆栈 - 在单独创建存储桶时更有意义堆栈,使用单独的模板(将桶URL放在"输出"部分),然后使用参数从原始堆栈引用它。

答案 1 :(得分:6)

只需在CloudFormation模板中添加一个输入参数即可指示应该使用现有的存储桶....除非您在使用该模板时尚未知道?然后,您可以根据参数值添加新资源。

答案 2 :(得分:1)

使用cloudformation可以使用Conditions 我创建了一个输入参数“ ShouldCreateBucketInputParameter”,然后使用CLI,您只需要设置“ true”或“ false”

Cloudformation json文件:

{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Description": "",
"Parameters": {
    "ShouldCreateBucketInputParameter": {
      "Type": "String",
      "AllowedValues": [
        "true",
        "false"
      ],
      "Description": "If true then the S3 bucket that will be proxied will be created with the CloudFormation stack."
    }
},
"Conditions": {
  "CreateS3Bucket": {
    "Fn::Equals": [
      {
        "Ref": "ShouldCreateBucketInputParameter"
      },
      "true"
    ]
  }
},
"Resources": {
    "SerialNumberBucketResource": {
        "Type": "AWS::S3::Bucket",
        "Condition": "CreateS3Bucket",
        "Properties": {
            "AccessControl": "Private"
        }
    }
},
"Outputs": {}
}

然后(我正在使用CLI部署堆栈)

aws cloudformation deploy --template ./s3BucketWithCondition.json --stack-name bucket-stack --parameter-overrides ShouldCreateBucketInputParameter="true" S3BucketNameInputParameter="BucketName22211"

答案 3 :(得分:0)

如果你做了更新,(可能是堆栈中的堆栈,也就是嵌套堆栈),未更改的部分不会更新。 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stack.html?icmpid=docs_cfn_console_designer

然后,您可以按照提及的方式设置策略以防止删除。 [记住'取消更新'回滚权限] https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html

还可以通过将堆栈输出添加到堆栈输出来了解交叉堆栈输出。 http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html 演练... http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/walkthrough-crossstackref.html

然后你需要使用Fn :: ImportValue ... http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html

这意味着可以使用网络堆栈名称参数。

不幸的是,当你在条件中试用它们时会出现这样的错误。

  

模板验证错误:模板错误:无法使用Fn :: ImportValue   在条件中。

或参数?

  

模板验证错误:模板格式错误:每个默认成员   必须是一个字符串。

尝试时也会发生这种情况......

  

模板格式错误:输出ExportOut格式错误。名称字段   Export不得依赖任何资源,导入值或   FN :: GetAZs。

因此,您无法停止从同一文件再次创建现有资源。仅在将其放入另一个堆栈并使用导出导入参考时。

但是如果你将两者分开,那么就会有一个依赖关系会停止和回滚,例如依赖关系的删除,这要归功于通过ImportValue函数的引用。

这里给出的例子是:

首先制作一个组模板

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Metadata": {
    "AWS::CloudFormation::Designer": {
      "6927bf3d-85ec-449d-8ee1-f3e1804d78f7": {
        "size": {
          "width": 60,
          "height": 60
        },
        "position": {
          "x": -390,
          "y": 130
        },
        "z": 0,
        "embeds": []
      },
      "6fe3a2b8-16a1-4ce0-b412-4d4f87e9c54c": {
        "source": {
          "id": "ac295134-9e38-4425-8d20-2c50ef0d51b3"
        },
        "target": {
          "id": "6927bf3d-85ec-449d-8ee1-f3e1804d78f7"
        },
        "z": 1
      }
    }
  },
  "Resources": {
    "TestGroup": {
      "Type": "AWS::IAM::Group",
      "Properties": {},
      "Metadata": {
        "AWS::CloudFormation::Designer": {
          "id": "6927bf3d-85ec-449d-8ee1-f3e1804d78f7"
        }
      },
      "Condition": ""
    }
  },
  "Parameters": {},
  "Outputs": {
    "GroupNameOut": {
      "Description": "The Group Name",
      "Value": {
        "Ref": "TestGroup"
      },
      "Export": {
        "Name": "Exported-GroupName"
      }
    }
  }
}

然后制作一个需要该组的用户模板。

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Metadata": {
    "AWS::CloudFormation::Designer": {
      "ac295134-9e38-4425-8d20-2c50ef0d51b3": {
        "size": {
          "width": 60,
          "height": 60
        },
        "position": {
          "x": -450,
          "y": 130
        },
        "z": 0,
        "embeds": [],
        "isrelatedto": [
          "6927bf3d-85ec-449d-8ee1-f3e1804d78f7"
        ]
      },
      "6fe3a2b8-16a1-4ce0-b412-4d4f87e9c54c": {
        "source": {
          "id": "ac295134-9e38-4425-8d20-2c50ef0d51b3"
        },
        "target": {
          "id": "6927bf3d-85ec-449d-8ee1-f3e1804d78f7"
        },
        "z": 1
      }
    }
  },
  "Resources": {
    "TestUser": {
      "Type": "AWS::IAM::User",
      "Properties": {
        "UserName": {
          "Ref": "UserNameParam"
        },
        "Groups": [
          {
            "Fn::ImportValue": "Exported-GroupName"
          }
        ]
      },
      "Metadata": {
        "AWS::CloudFormation::Designer": {
          "id": "ac295134-9e38-4425-8d20-2c50ef0d51b3"
        }
      }
    }
  },
  "Parameters": {
    "UserNameParam": {
      "Default": "testerUser",
      "Description": "Username For Test",
      "Type": "String",
      "MinLength": "1",
      "MaxLength": "16",
      "AllowedPattern": "[a-zA-Z][a-zA-Z0-9]*",
      "ConstraintDescription": "must begin with a letter and contain only alphanumeric characters."
    }
  },
  "Outputs": {
    "UserNameOut": {
      "Description": "The User Name",
      "Value": {
        "Ref": "TestUser"
      }
    }
  }
}

你会得到

  

找不到名为Exported-GroupName的导出。用户请求回滚。

如果运行没有找到组的用户已导出。

然后,您可以使用嵌套堆栈方法。

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Metadata": {
    "AWS::CloudFormation::Designer": {
      "66470873-b2bd-4a5a-af19-5d54b11f48ef": {
        "size": {
          "width": 60,
          "height": 60
        },
        "position": {
          "x": -815,
          "y": 169
        },
        "z": 0,
        "embeds": []
      },
      "ed1de011-f1bb-4788-b63e-dcf5494d10d1": {
        "size": {
          "width": 60,
          "height": 60
        },
        "position": {
          "x": -710,
          "y": 170
        },
        "z": 0,
        "dependson": [
          "66470873-b2bd-4a5a-af19-5d54b11f48ef"
        ]
      },
      "c978f2d9-3fb2-4420-b255-74941f10a28a": {
        "source": {
          "id": "ed1de011-f1bb-4788-b63e-dcf5494d10d1"
        },
        "target": {
          "id": "66470873-b2bd-4a5a-af19-5d54b11f48ef"
        },
        "z": 1
      }
    }
  },
  "Resources": {
    "GroupStack": {
      "Type": "AWS::CloudFormation::Stack",
      "Properties": {
        "TemplateURL": "https://s3-us-west-2.amazonaws.com/cf-templates-x-TestGroup.json"
      },
      "Metadata": {
        "AWS::CloudFormation::Designer": {
          "id": "66470873-b2bd-4a5a-af19-5d54b11f48ef"
        }
      }
    },
    "UserStack": {
      "Type": "AWS::CloudFormation::Stack",
      "Properties": {
        "TemplateURL": "https://s3-us-west-2.amazonaws.com/cf-templates-x-TestUserFindsGroup.json"
      },
      "Metadata": {
        "AWS::CloudFormation::Designer": {
          "id": "ed1de011-f1bb-4788-b63e-dcf5494d10d1"
        }
      },
      "DependsOn": [
        "GroupStack"
      ]
    }
  }
}

不幸的是,您仍然可以删除用户堆栈,即使它是由MultiStack在此示例中制作的,但具有删除策略和其他可能有帮助的东西。

然后您只更新它创建的各种堆栈,如果您重新使用Bucket,则不会执行Multi Stack。

否则,您将以各种方式查看API和脚本。

答案 4 :(得分:0)

如果您想将一些现有资源合并到 CF 中,很遗憾这是不可能的。如果您只想将一组资源作为模板的一部分,取决于一些参数,你可以使用Conditions。但它们并没有改变CF本身的性质,只是确定需要哪些资源,而不是采取什么行动,也无法事先判断资源是否存在。

答案 5 :(得分:0)

没有明确说明的东西。如果您的第一次部署失败,除非您有 at 保留策略,否则资源将被删除。在这种情况下,手动删除相关资源是安全的。下一次部署将重新创建它,而不会产生资源已经存在的错误。