CloudFormation:如果资源不存在则创建资源,但不删除它们
CloudFormation: Create resources if they do not exist, but do not delete them
我有以下 CloudFormation 模板。 (它基于默认为 AWS Lambda 中的 运行ning C# Web API 创建的模板,但这可能不相关。)
它创建一个 AWS Lambda 函数。如果现有资源的名称未作为参数提供,该模板还会创建一个 IAM 角色和一个 DynamoDB table。
这部分有效。如果没有为角色提供名称并且 table,则创建它们。
我运行第二次对模板执行更新时存在问题:此时,我的角色和table存在,所以我提供名称作为参数。然而,当 CloudFormation 运行 第二次时,它第一次创建的资源(角色和 table)被删除。
有没有什么方法可以设置模板,使其在资源不存在时创建新资源,但在资源已经存在时不删除它们?
我对 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 网关之前手动创建资源,但看起来我正在尝试做的事情应该是可能的。
更新现有堆栈时,请勿更改参数。因此,即使在更新堆栈时,也请将 ShouldCreateTable
设置为 true
。
是的,当 table 已经存在时,将堆栈更新为 "Create a table" 似乎违反直觉,但您需要这样做。
原因是这样的:
- 创建堆栈时,将
ShouldCreateTable
设置为 true
,模板应用它的条件逻辑并创建 table 作为它自己的托管资源。
- 更新堆栈时,您将
ShouldCreateTable
设置为 false
,模板应用它的条件逻辑并确定您不再需要托管 table,因为您提供你自己的现在。应删除该资源。它不承认 table 是相同的。
使用您的模板时,如果您要提供自己创建的table ,请只说 ShouldCreateTable
== false
。
我有以下 CloudFormation 模板。 (它基于默认为 AWS Lambda 中的 运行ning C# Web API 创建的模板,但这可能不相关。)
它创建一个 AWS Lambda 函数。如果现有资源的名称未作为参数提供,该模板还会创建一个 IAM 角色和一个 DynamoDB table。
这部分有效。如果没有为角色提供名称并且 table,则创建它们。
我运行第二次对模板执行更新时存在问题:此时,我的角色和table存在,所以我提供名称作为参数。然而,当 CloudFormation 运行 第二次时,它第一次创建的资源(角色和 table)被删除。
有没有什么方法可以设置模板,使其在资源不存在时创建新资源,但在资源已经存在时不删除它们?
我对 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 网关之前手动创建资源,但看起来我正在尝试做的事情应该是可能的。
更新现有堆栈时,请勿更改参数。因此,即使在更新堆栈时,也请将 ShouldCreateTable
设置为 true
。
是的,当 table 已经存在时,将堆栈更新为 "Create a table" 似乎违反直觉,但您需要这样做。
原因是这样的:
- 创建堆栈时,将
ShouldCreateTable
设置为true
,模板应用它的条件逻辑并创建 table 作为它自己的托管资源。 - 更新堆栈时,您将
ShouldCreateTable
设置为false
,模板应用它的条件逻辑并确定您不再需要托管 table,因为您提供你自己的现在。应删除该资源。它不承认 table 是相同的。
使用您的模板时,如果您要提供自己创建的table ,请只说 ShouldCreateTable
== false
。