如何使 CloudFormation 模板中的整个对象可选?

Dav*_*vid 2 json aws-cloudformation aws-lambda

我正在通过 CloudFormation 模板创建一个 Lambda 函数,并且我希望可以选择输入 VpcConfig 属性的信息。我找到了这样一篇关于如何使参数可选的文章:

https://cloudonaut.io/optional-parameter-in-cloudformation/

这对于查找使具有单个值的属性可选(如单个字符串值)的语法非常有帮助。

但我需要弄清楚的是如何使整个 VpcConfig OBJECT 成为可选的。

这有点棘手,因为 VpcConfig 对象有两个属性:SecurityGroupIds 和 SubnetIds。并且两者都是必需的。所以用户需要输入这两个或两个都不输入。如果两者都没有输入,那么整个 VpcConfig 对象应该是空的,或者不存在(这应该没问题,因为 VpConfig 对象本身是可选的)。

这是我现在所拥有的截断版本,但这还不够,因为我仍然收到错误消息,说 SecurityGroupIds 和 SubnetIds 不能有空值,因为只要 VpcConfig 属性中存在对象,就需要它们:

"Conditions": {
        "HasSecurityGroups": {"Fn::Not": [{"Fn::Equals": [{"Fn::Join": ["", {"Ref": "SecurityGroupIds"}]}, ""]}]},
        "HasSubnetIds": {"Fn::Not": [{"Fn::Equals": [{"Fn::Join": ["", {"Ref": "SubnetIds"}]}, ""]}]}
      },
Run Code Online (Sandbox Code Playgroud)

然后在 Lambda 资源中:

"VpcConfig" : {
          "SecurityGroupIds" : {"Fn::If": ["HasSecurityGroups", {"Ref": "SecurityGroupIds"}, {"Ref": "AWS::NoValue"}]},
          "SubnetIds" : {"Fn::If": ["HasSubnetIds", {"Ref": "SubnetIds"}, {"Ref": "AWS::NoValue"}]}
        },
Run Code Online (Sandbox Code Playgroud)

这是整个模板,如果有帮助的话:

 {
  "AWSTemplateFormatVersion" : "2010-09-09",

  "Description" : "Lambda template for testing purposes",

  "Parameters" : {
    "S3BucketName" : {
      "Type" : "String",
      "Description" : "The name of the Amazon S3 bucket where the .zip file that contains your deployment package is stored."
    },
    "S3FileLocation" : {
      "Type" : "String",
      "Description" : "The location and name of the .zip file that contains your source code."
    },
    "S3ObjectVersion" : {
      "Type" : "String",
      "Description" : "If you have S3 versioning enabled, the version ID of the zip file that contains your source code."
    },
    "DeadLetterArn" : {
      "Type" : "String",
      "Description" : "ARN that specifies a Dead Letter Queue (DLQ) that Lambda sends events to when it can't process them. For example, you can send unprocessed events to an Amazon Simple Notification Service (Amazon SNS) topic, where you can take further action."
    },
    "EnvironmentVariable" : {
      "Type" : "String",
      "Default" : "test",
      "Description" : "Environment Variable"
    },
    "KmsKeyArn" : {
      "Type" : "String",
      "Description" : "KMS Key ARN if environment variables are encrypted"
    },
    "HandlerFunctionName" : {
      "Type" : "String",
      "Description" : "Name of function to initiate the Lambda"
    },
    "MemorySize" : {
      "Type" : "Number",
      "Description" : "Number of MB to allocate to the Lambda function",
      "ConstraintDescription" : "Multiples of 64, between 128 and 3008",
      "MinValue" : "128",
      "Default" : "128"
    },
    "SecurityGroupIds" : {
      "Type" : "CommaDelimitedList",
      "Description" : "A list of one or more security groups IDs in the VPC that includes the resources to which your Lambda function requires access."
    },
    "SubnetIds" : {
      "Type" : "CommaDelimitedList",
      "Description" : "A list of one or more subnet IDs in the VPC that includes the resources to which your Lambda function requires access."
    },
    "Role" : {
      "Type" : "String",
      "Description" : "ARN of Lambda Role"
    },
    "FuncName" : {
      "Type" : "String",
      "Description" : "Name of the the new Lambda function?"
    }
  },

  "Conditions": {
    "HasSecurityGroups": {"Fn::Not": [{"Fn::Equals": [{"Fn::Join": ["", {"Ref": "SecurityGroupIds"}]}, ""]}]},
    "HasSubnetIds": {"Fn::Not": [{"Fn::Equals": [{"Fn::Join": ["", {"Ref": "SubnetIds"}]}, ""]}]}
  },

  "Resources" : {

    "LambdaFunction" : {
      "Type" : "AWS::Lambda::Function",
      "Properties" : {
        "Code" : {
          "S3Bucket" : { "Ref" : "S3BucketName" },
          "S3Key" : { "Ref" : "S3FileLocation" },
          "S3ObjectVersion" : { "Ref" : "S3ObjectVersion" }
        },
        "DeadLetterConfig" : {
          "TargetArn" : { "Ref" : "DeadLetterArn" }
        },
        "Description" : "Lambda",
        "Environment" : {
          "Variables" : {
            "SomeVariable": {
              "Ref" : "EnvironmentVariable"
            }  
          }
        },
        "FunctionName" : { "Ref" : "FuncName" },
        "Handler" : { "Ref" : "HandlerFunctionName" },
        "KmsKeyArn" : { "Ref" : "KmsKeyArn" },
        "MemorySize" : { "Ref" : "MemorySize" },
        "Role" : { "Ref" : "Role" },
        "Runtime" : "python3.6",
        "VpcConfig" : {
          "SecurityGroupIds" : {"Fn::If": ["HasSecurityGroups", {"Ref": "SecurityGroupIds"}, {"Ref": "AWS::NoValue"}]},
          "SubnetIds" : {"Fn::If": ["HasSubnetIds", {"Ref": "SubnetIds"}, {"Ref": "AWS::NoValue"}]}
        },
        "Tags" : [ {
          "Key" : "test",
          "Value" : "true"
        } ]
      }
    }
  },
  "Outputs" : {
    "LambdaFunction" : {
      "Description" : "Lambda function",
      "Value" : { "Ref" : "LambdaFunction" },
      "Export" : {
        "Name" : {"Fn::Sub": "${AWS::StackName}-Lambda" }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

更新:cementblocks 在下面发布的答案适用于 AWS GUI 控制台,但不幸的是,如果您尝试使用 CLI 部署模板,它仍然会遇到同样的问题。我在下面的链接上创建了一个新问题来单独解决这个问题,因为我想他的回答对大多数引用这篇文章的人来说都是有用的。

使用 AWS CLI 启动 CloudFormation 模板时的可选参数

cem*_*cks 5

创建第三个条件HasVPC,当 HasSecurityGroups 和 HasSubnetIds 都为真时,它应该为真Fn::And。您将不得不复制条件语句;你不能在另一个条件下引用。

然后使用设置 vpcConfig 属性 Fn::If

"VpcConfig": {
  "Fn::If": [
    "HasVPC",
    {
      "SecurityGroupIds" : {"Ref": "SecurityGroupIds"},
      "SubnetIds" : {"Ref": "SubnetIds"}
    },
    { "Ref":"AWS::NoValue" }
  ]
}
Run Code Online (Sandbox Code Playgroud)

您可以删除HasSecurityGroupsandHasSubnetIds条件,除非您在其他地方使用它们。