我从cfncluster创建的堆栈中提取了一个CloudFormation模板。我正在尝试简化和分组参数,以便将强制参数组合在一起并且是非冗余的。默认的子网相关参数包括MasterSubnetId,AvailabilityZone,ComputeSubnetId和ComputeSubnetCidr。模板使用这些来计算几个条件,并在几个资源上设置AvailabilityZone属性:
"CreateComputeSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
},
{
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
}
]
}
]
},
"UseComputeSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
},
{
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
}
]
}
]
},
"UseMasterSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
},
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
}
]
},
我想简化模板以要求MasterSubnetId或AvailabilityZone,但不是两者都要求。我不需要提供一个或另一个的选项,我可以要求其中一个。主要问题是我无法弄清楚如何做到这一点。模板使用的各种资源似乎都需要两者,即使它们应该是相关的。我不能像我想要的那样使用Fn::GetAtt
,因为第一个参数不能来自函数,如:
"Fn::GetAtt" : [ { "Ref": "MasterSubnetId" }, "AvailabilityZone" ]
此外,我希望计算机队始终拥有自己的子网。
以下是模板的子网相关部分:
{
...snip...
"Parameters": {
"ComputeSubnetId": {
"Description": "ID of the Subnet you want to provision the Compute Servers into. Set to NONE to use the same subnet as Master Server.",
"Type": "String",
"Default": "NONE"
},
"ComputeSubnetCidr": {
"Description": "CIDR(s) for new backend subnet(s) i.e. 10.0.100.0/24. This is a comma-delimited list and can support multiple CIDR ranges for a multi-AZ cluster. The order and length of this list MUST match the AvailabilityZones parameter. Set to NONE to use the same subnet as Master Server.",
"Type": "String",
"ConstraintDescription": "must be a valid CIDR range of the form x.x.x.x/x.",
"AllowedPattern": "(NONE|(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2}))",
"Default": "NONE"
},
"MasterSubnetId": {
"Description": "ID of the Subnet you want to provision the Master server into",
"Type": "AWS::EC2::Subnet::Id"
},
"AvailabilityZone": {
"Description": "Availability Zone the cluster will launch into. THIS IS REQUIRED",
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"VPCId": {
"Description": "ID of the VPC you want to provision cluster into. Only used with UseVPCBase=false",
"Type": "AWS::EC2::VPC::Id"
},
"UsePublicIps": {
"Description": "Boolean flag to use public IP's for instances. If false, the VPC must be correctly setup to use NAT for all traffic.",
"Type": "String",
"Default": "true",
"ConstraintDescription": "true/false",
"AllowedValues": [
"true",
"false"
]
}
},
"Conditions": {
"CreateComputeSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
},
{
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
}
]
}
]
},
"UseComputeSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
},
{
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
}
]
}
]
},
"UseMasterSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
},
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
}
]
}
},
"Mappings": {
"AWSInstanceType2Capabilites": {
...snip...
},
"AWSRegionOS2AMI": {
...snip...
},
"OSFeatures": {
...snip...
},
"CfnClusterVersions": {
"default": {
"cfncluster": "cfncluster-1.1.0",
"cookbook": "cfncluster-cookbook-1.1.0",
"chef": "12.4.3",
"ridley": "4.3.2",
"berkshelf": "4.0.1",
"ami": "201602192042"
}
},
"AWSRegion2Capabilites": {
...snip...
}
},
"Resources": {
...snip...
"CfnClusterPolicies": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "cfncluster",
"PolicyDocument": {
"Statement": [
{
"Sid": "EC2",
"Action": [
"ec2:AttachVolume",
"ec2:DescribeInstanceAttribute",
"ec2:DescribeInstanceStatus",
"ec2:DescribeInstances"
],
"Effect": "Allow",
"Resource": [
"*"
]
},
...snip...
]
},
"Roles": [
{
"Ref": "RootRole"
}
]
},
"Condition": "CreateEC2IAMRole",
},
"MasterEIP": {
"Type": "AWS::EC2::EIP",
"Properties": {
"Domain": "vpc"
},
"Condition": "MasterPublicIp",
},
"MasterServer": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": {
"Ref": "MasterInstanceType"
},
"BlockDeviceMappings": [
...snip...
],
"KeyName": {
"Ref": "KeyName"
},
"Tags": [
{
"Key": "Application",
"Value": {
"Ref": "AWS::StackName"
}
},
{
"Key": "Name",
"Value": "Master"
}
],
"NetworkInterfaces": [
{
"NetworkInterfaceId": {
"Ref": "MasterENI"
},
"DeviceIndex": "0"
}
],
"ImageId": {
"Fn::If": [
"UseCustomAMI",
{
"Ref": "CustomAMI"
},
{
"Fn::FindInMap": [
"AWSRegionOS2AMI",
{
"Ref": "AWS::Region"
},
{
"Ref": "BaseOS"
}
]
}
]
},
"UserData": {
...snip...
}
}
},
"Metadata": {
"Comment": "cfncluster Master server",
"AWS::CloudFormation::Init": {
"configSets": {
"default": [
"deployConfigFiles",
"getCookbooks",
"chefPrepEnv",
"shellRunPreInstall",
"chefConfig",
"shellRunPostInstall",
"shellForkClusterReadyInstall"
]
},
"deployConfigFiles": {
"files": {
"/tmp/dna.json": {
"mode": "000644",
"owner": "root",
"group": "root",
"content": {
"cfncluster": {
"stack_name": {
"Ref": "AWS::StackName"
},
"cfn_preinstall": {
"Ref": "PreInstallScript"
},
"cfn_preinstall_args": {
"Ref": "PreInstallArgs"
},
"cfn_postinstall": {
"Ref": "PostInstallScript"
},
"cfn_postinstall_args": {
"Ref": "PostInstallArgs"
},
"cfn_region": {
"Ref": "AWS::Region"
},
"cfn_volume": {
"Fn::If": [
"UseExistingEBSVolume",
{
"Ref": "EBSVolumeId"
},
{
"Ref": "SharedVolume"
}
]
},
"cfn_scheduler": {
"Ref": "Scheduler"
},
"cfn_encrypted_ephemeral": {
"Ref": "EncryptedEphemeral"
},
"cfn_ephemeral_dir": {
"Ref": "EphemeralDir"
},
"cfn_shared_dir": {
"Ref": "SharedDir"
},
"cfn_proxy": {
"Ref": "ProxyServer"
},
"cfn_node_type": "MasterServer",
"cfn_cluster_user": {
"Fn::FindInMap": [
"OSFeatures",
{
"Ref": "BaseOS"
},
"User"
]
},
"cfn_ddb_table": {
"Ref": "DynamoDBTable"
},
"cfn_sqs_queue": {
"Fn::GetAtt": [
"SQS",
"QueueName"
]
}
},
"run_list": {
"Fn::If": [
"UseCustomRunList",
{
"Ref": "CustomChefRunList"
},
{
"Fn::Join": [
"",
[
"recipe[cfncluster::",
{
"Ref": "Scheduler"
},
"_config]"
]
]
}
]
}
}
},
...snip...
},
"commands": {
...snip...
}
},
...snip...
},
},
"CreationPolicy": {
"ResourceSignal": {
"Count": "1",
"Timeout": "PT30M"
}
}
},
"ComputeFleet": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"MaxSize": {
"Ref": "MaxQueueSize"
},
"AvailabilityZones": [
{
"Ref": "AvailabilityZone"
}
],
"VPCZoneIdentifier": [
{
"Fn::If": [
"UseMasterSubnetForCompute",
{
"Ref": "MasterSubnetId"
},
{
"Fn::If": [
"CreateComputeSubnetForCompute",
{
"Ref": "ComputeSubnet"
},
{
"Ref": "ComputeSubnetId"
}
]
}
]
}
],
...snip...
},
"DependsOn": "MasterServer",
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT30M",
"Count": {
"Ref": "ComputeWaitConditionCount"
}
}
},
},
"ComputeServerLaunchConfig": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Properties": {
"SecurityGroups": [
{
"Fn::If": [
"CreateSecurityGroups",
{
"Ref": "ComputeSecurityGroup"
},
{
"Ref": "AWS::NoValue"
}
]
},
{
"Fn::If": [
"AddAdditionalSG",
{
"Ref": "AdditionalSG"
},
{
"Ref": "AWS::NoValue"
}
]
},
{
"Fn::If": [
"UseExistingSecurityGroup",
{
"Ref": "VPCSecurityGroupId"
},
{
"Ref": "AWS::NoValue"
}
]
}
],
...snip...
},
"Metadata": {
"Comment": "cfncluster Compute server",
"AWS::CloudFormation::Init": {
"configSets": {
"default": [
"deployConfigFiles",
"getCookbooks",
"chefPrepEnv",
"shellRunPreInstall",
"chefConfig",
"shellRunPostInstall",
"shellForkClusterReadyInstall",
"signalComputeReady"
]
},
"deployConfigFiles": {
"files": {
"/tmp/dna.json": {
"mode": "000644",
"owner": "root",
"group": "root",
"content": {
"cfncluster": {
"stack_name": {
"Ref": "AWS::StackName"
},
"cfn_preinstall": {
"Ref": "PreInstallScript"
},
"cfn_preinstall_args": {
"Ref": "PreInstallArgs"
},
"cfn_postinstall": {
"Ref": "PostInstallScript"
},
"cfn_postinstall_args": {
"Ref": "PostInstallArgs"
},
"cfn_region": {
"Ref": "AWS::Region"
},
"cfn_scheduler": {
"Ref": "Scheduler"
},
"cfn_encrypted_ephemeral": {
"Ref": "EncryptedEphemeral"
},
"cfn_ephemeral_dir": {
"Ref": "EphemeralDir"
},
"cfn_shared_dir": {
"Ref": "SharedDir"
},
"cfn_proxy": {
"Ref": "ProxyServer"
},
"cfn_sqs_queue": {
"Ref": "SQS"
},
"cfn_master": {
"Fn::GetAtt": [
"MasterServer",
"PrivateDnsName"
]
},
"cfn_node_type": "ComputeFleet",
"cfn_cluster_user": {
"Fn::FindInMap": [
"OSFeatures",
{
"Ref": "BaseOS"
},
"User"
]
}
},
"run_list": {
"Fn::If": [
"UseCustomRunList",
{
"Ref": "CustomChefRunList"
},
{
"Fn::Join": [
"",
[
"recipe[cfncluster::",
{
"Ref": "Scheduler"
},
"_config]"
]
]
}
]
}
}
},
...snip...
},
"commands": {
...snip...
}
},
...snip...
}
},
...snip...
"ComputeSubnet": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPCId"
},
"CidrBlock": {
"Ref": "ComputeSubnetCidr"
},
"Tags": [
{
"Key": "Network",
"Value": "ComputeSubnet"
}
],
"AvailabilityZone": {
"Ref": "AvailabilityZone"
}
},
"Condition": "CreateComputeSubnetForCompute",
},
"ComputeRouteTable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "VPCId"
},
"Tags": [
{
"Key": "Application",
"Value": {
"Ref": "AWS::StackName"
}
},
{
"Key": "Network",
"Value": "ComputeSubnet"
}
]
},
"Condition": "CreateComputeSubnetForCompute",
},
"ComputeRoute": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "ComputeRouteTable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"NetworkInterfaceId": {
"Ref": "MasterENI"
}
},
"Condition": "CreateComputeSubnetForCompute",
},
"ComputeSubnetRouteTableAssociation": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "ComputeSubnet"
},
"RouteTableId": {
"Ref": "ComputeRouteTable"
}
},
"Condition": "CreateComputeSubnetForCompute",
},
"MasterSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Enable access to the Master host",
"VpcId": {
"Ref": "VPCId"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {
"Ref": "AccessFrom"
}
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": {
"Ref": "AccessFrom"
}
}
]
},
"Condition": "CreateSecurityGroups",
},
"MasterSecurityGroupIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"IpProtocol": "-1",
"FromPort": "0",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Ref": "ComputeSecurityGroup"
},
"GroupId": {
"Ref": "MasterSecurityGroup"
}
},
"Condition": "CreateSecurityGroups",
},
"ComputeSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow access to resources in subnets behind front",
"VpcId": {
"Ref": "VPCId"
},
"SecurityGroupIngress": [
{
"SourceSecurityGroupId": {
"Ref": "MasterSecurityGroup"
},
"IpProtocol": "-1",
"FromPort": "0",
"ToPort": "65535"
}
]
},
"Condition": "CreateSecurityGroups",
},
"ComputeSecurityGroupIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"IpProtocol": "-1",
"FromPort": "0",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Ref": "ComputeSecurityGroup"
},
"GroupId": {
"Ref": "ComputeSecurityGroup"
}
},
"Condition": "CreateSecurityGroups"
},
"MasterENI": {
"Type": "AWS::EC2::NetworkInterface",
"Properties": {
"Description": "cfncluster Master Server",
"SubnetId": {
"Ref" : "MasterSubnetId"
},
"SourceDestCheck": "false",
"GroupSet": [
{
"Fn::If": [
"CreateSecurityGroups",
{
"Ref": "MasterSecurityGroup"
},
{
"Ref": "AWS::NoValue"
}
]
},
{
"Fn::If": [
"AddAdditionalSG",
{
"Ref": "AdditionalSG"
},
{
"Ref": "AWS::NoValue"
}
]
},
{
"Fn::If": [
"UseExistingSecurityGroup",
{
"Ref": "VPCSecurityGroupId"
},
{
"Ref": "AWS::NoValue"
}
]
}
]
},
},
"SharedVolume": {
"Type": "AWS::EC2::Volume",
"Properties": {
"AvailabilityZone": {
"Ref": "AvailabilityZone"
},
"VolumeType": {
"Ref": "VolumeType"
},
"Size": {
"Fn::If": [
"UseEBSSnapshot",
{
"Ref": "AWS::NoValue"
},
{
"Ref": "VolumeSize"
}
]
},
...snip...
},
...snip...
},
...snip...