【问题标题】:CloudFormation: Create resources if they do not exist, but do not delete themCloudFormation:如果资源不存在则创建,但不要删除它们
【发布时间】:2017-12-22 04:43:30
【问题描述】:

我有以下 CloudFormation 模板。 (它基于默认为在 AWS Lambda 中运行 C# Web API 而创建的模板,但这可能不相关。)

它创建一个 AWS Lambda 函数。如果现有资源的名称未作为参数提供,该模板还会创建一个 IAM 角色和一个 DynamoDB 表。

那部分有效。如果没有为角色和表提供名称,则会创建它们。

当我第二次运行模板以执行更新时出现问题:此时,我的角色和表存在,所以我提供名称作为参数。但是,当 CloudFormation 第二次运行时,它第一次创建的资源(角色和表)会被删除。

有没有办法设置模板,如果它们不存在,它会创建新资源,但如果它们已经存在,则不会删除它们?

我在 CloudFormation 方面做得不多,但我确实浏览了文档。我找到的最接近的是setting a stack policy,但它似乎不是模板的一部分。看来我必须事后在管理控制台中执行此操作。

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Transform" : "AWS::Serverless-2016-10-31",
  "Description" : "...",

  "Parameters" : {
    "ShouldCreateTable" : {
      "Type" : "String",        
      "AllowedValues" : ["true", "false"],
      "Description" : "If true then the underlying DynamoDB table will be created with the CloudFormation stack."
    },  
    "TableName" : {
        "Type" : "String",
        "Description" : "Name of DynamoDB table to be used for underlying data store. If left blank a new table will be created.",
        "MinLength" : "0"
    },
    "ShouldCreateRole" : {
      "Type" : "String",        
      "AllowedValues" : ["true", "false"],
      "Description" : "If true then the role for the Lambda function will be created with the CloudFormation stack."
    },  
    "RoleARN" : {
        "Type" : "String",
        "Description" : "ARN of the IAM Role used to run the Lambda function. If left blank a new role will be created.",
        "MinLength" : "0"
    }
  },

  "Conditions" : {
    "CreateDynamoTable" : {"Fn::Equals" : [{"Ref" : "ShouldCreateTable"}, "true"]},
    "TableNameGenerated" : {"Fn::Equals" : [{"Ref" : "TableName"}, ""]},
    "CreateRole":{"Fn::Equals" : [{"Ref" : "ShouldCreateRole"}, "true"]},
    "RoleGenerated" : {"Fn::Equals" : [{"Ref" : "RoleARN"}, ""]}
  },

  "Resources" : {

    "Get" : {
      "Type" : "AWS::Serverless::Function",
      "Properties": {
        ...
        "Role": {"Fn::If" : ["CreateRole", {"Fn::GetAtt":["LambdaRole", "Arn"]}, {"Ref":"RoleARN"}]},
        "Environment" : {
          "Variables" : {
            "AppDynamoTable" : { "Fn::If" : ["CreateDynamoTable", {"Ref":"DynamoTable"}, { "Ref" : "TableName" } ] }
          }
        },
        ...
      }
    },

    "LambdaRole":{
        "Type":"AWS::IAM::Role",
        "Condition":"CreateRole",
        "Properties":{
            "ManagedPolicyArns":["arn:aws:iam::aws:policy/AWSLambdaFullAccess"],
            "AssumeRolePolicyDocument": {
               "Version" : "2012-10-17",
               "Statement": [ {
                  "Effect": "Allow",
                  "Principal": {
                     "Service": [ "lambda.amazonaws.com" ]
                  },
                  "Action": [ "sts:AssumeRole" ]
               } ]
            },
            "Policies": [  {
                "PolicyName": "root",
                "PolicyDocument": {
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Effect": "Allow",
                                "Action": [
                                    "dynamodb:Query",
                                    "dynamodb:Scan",
                                    "dynamodb:PutItem",
                                    "dynamodb:GetItem",
                                    "dynamodb:UpdateItem",
                                    "dynamodb:DeleteItem",
                                    "logs:CreateLogGroup",
                                    "logs:CreateLogStream",
                                    "logs:PutLogEvents"
                                ],
                                "Resource": [
                                    "*"
                                ]
                            }
                        ]
                    }
                }
            ]
        }
    },

    "DynamoTable" : {
        "Type" : "AWS::DynamoDB::Table",
        "Condition" : "CreateDynamoTable",
        "Properties" : {
            "TableName" : { "Fn::If" : ["TableNameGenerated", {"Ref" : "AWS::NoValue" }, { "Ref" : "TableName" } ] },
            "AttributeDefinitions": [
                { "AttributeName" : "id", "AttributeType" : "S" }
            ],
            "KeySchema" : [
                { "AttributeName" : "id", "KeyType" : "HASH"}
            ],          
            "ProvisionedThroughput" : { "ReadCapacityUnits" : "5", "WriteCapacityUnits" : "5" }
        }
    }
  },

  "Outputs" : {
    "UnderlyingDynamoTable" : {
        "Value" : { "Fn::If" : ["CreateDynamoTable", {"Ref":"DynamoTable"}, { "Ref" : "TableName" } ] }
    },
    "LambdaRole" : {
        "Value" : {"Fn::If" : ["CreateRole", {"Fn::GetAtt":["LambdaRole", "Arn"]}, {"Ref":"RoleARN"} ] }
    }
  }
}

我可以删除创建步骤并在 API 网关之前手动创建资源,但我想要做的似乎应该是可能的。

【问题讨论】:

    标签: amazon-web-services aws-sdk amazon-cloudformation


    【解决方案1】:

    更新现有堆栈时,请勿更改参数。因此,即使您正在更新堆栈,也请将 ShouldCreateTable 设置为 true

    是的,当一个表已经存在时,更新你的堆栈说“创建一个表”似乎违反直觉,但你需要这样做。

    原因是这样的:

    1. 创建堆栈时,将ShouldCreateTable 设置为true,模板应用其条件逻辑并将表创建为自己的托管资源。
    2. 更新堆栈时,您将ShouldCreateTable 设置为false,模板应用其条件逻辑并确定您不再需要托管表,因为您现在提供自己的表。应该删除资源。它不承认该表是相同的。

    使用您的模板时,如果您要提供自己您创建的表格,请仅说ShouldCreateTable == false

    【讨论】:

    猜你喜欢
    • 2019-07-26
    • 2021-04-05
    • 1970-01-01
    • 2016-09-18
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    相关资源
    最近更新 更多