Skip to content

Commit

Permalink
feat(aws-ec2): control over VPC AZs
Browse files Browse the repository at this point in the history
With this change, the `Vpc` construct gains a new constructor prop,
`availabilityZones`, which gives more control over AZs than the existing
`maxAzs` prop.

closes aws#5847
  • Loading branch information
philipmw committed Jun 6, 2022
1 parent 15bcc3c commit e3d3dd4
Show file tree
Hide file tree
Showing 10 changed files with 812 additions and 4 deletions.
4 changes: 3 additions & 1 deletion packages/@aws-cdk/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ const vpc = new ec2.Vpc(this, 'TheVPC', {
// The IP space will be divided over the configured subnets.
cidr: '10.0.0.0/21',

// 'maxAzs' configures the maximum number of availability zones to use
// 'maxAzs' configures the maximum number of availability zones to use.
// If you want to specify the exact availability zones you want the VPC
// to use, use `availabilityZones` instead.
maxAzs: 3,

// 'subnetConfiguration' specifies the "subnet groups" to create.
Expand Down
33 changes: 30 additions & 3 deletions packages/@aws-cdk/aws-ec2/lib/vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -841,10 +841,21 @@ export interface VpcProps {
* only 2 AZs, so to use more than 2 AZs, be sure to specify the account and
* region on your stack.
*
* Specify this option only if you do not specify `availabilityZones`.
*
* @default 3
*/
readonly maxAzs?: number;

/**
* Availability zones this VPC spans.
*
* Specify this option only if you do not specify `maxAzs`.
*
* @default - a subset of AZs of the stack
*/
readonly availabilityZones?: string[];

/**
* The number of NAT Gateways/Instances to create.
*
Expand Down Expand Up @@ -1289,6 +1300,10 @@ export class Vpc extends VpcBase {
throw new Error('To use DNS Hostnames, DNS Support must be enabled, however, it was explicitly disabled.');
}

if (props.availabilityZones && props.maxAzs) {
throw new Error('Vpc supports \'availabilityZones\' or \'maxAzs\', but not both.');
}

const cidrBlock = ifUndefined(props.cidr, Vpc.DEFAULT_CIDR_RANGE);
if (Token.isUnresolved(cidrBlock)) {
throw new Error('\'cidr\' property must be a concrete CIDR string, got a Token (we need to parse it for automatic subdivision)');
Expand Down Expand Up @@ -1317,10 +1332,22 @@ export class Vpc extends VpcBase {

Tags.of(this).add(NAME_TAG, props.vpcName || this.node.path);

this.availabilityZones = stack.availabilityZones;
if (props.availabilityZones) {
// If given AZs and stack AZs are both resolved, then validate their compatibility.
const resolvedStackAzs = stack.availabilityZones.filter(az => !Token.isUnresolved(az));
const areGivenAzsSubsetOfStack = resolvedStackAzs.length === 0 // stack AZs are tokenized, so we cannot validate it
|| props.availabilityZones.every(
az => Token.isUnresolved(az) // given AZ is tokenized, such as in integ tests, so we cannot validate it
|| resolvedStackAzs.includes(az));
if (!areGivenAzsSubsetOfStack) {
throw new Error(`Given VPC 'availabilityZones' ${props.availabilityZones} must be a subset of the stack's availability zones ${stack.availabilityZones}`);
}
this.availabilityZones = props.availabilityZones;
} else {
const maxAZs = props.maxAzs ?? 3;
this.availabilityZones = stack.availabilityZones.slice(0, maxAZs);
}

const maxAZs = props.maxAzs ?? 3;
this.availabilityZones = this.availabilityZones.slice(0, maxAZs);

this.vpcId = this.resource.ref;
this.vpcArn = Arn.format({
Expand Down
11 changes: 11 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/integ.vpc-azs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as cdk from '@aws-cdk/core';
import * as ec2 from '../lib';

const app = new cdk.App();
const stack = new cdk.Stack(app, 'aws-cdk-ec2-vpc-azs');

new ec2.Vpc(stack, 'MyVpc', {
availabilityZones: [stack.availabilityZones[1]],
});

app.synth();
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "20.0.0",
"files": {
"77e3ec18ea13d0b9b35f46a46f01b621e0df5c75fdad25fb81a3ffef3a6f1a17": {
"source": {
"path": "aws-cdk-ec2-vpc-azs.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "77e3ec18ea13d0b9b35f46a46f01b621e0df5c75fdad25fb81a3ffef3a6f1a17.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
}
},
"dockerImages": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
{
"Resources": {
"MyVpcF9F0CA6F": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.0.0.0/16",
"EnableDnsHostnames": true,
"EnableDnsSupport": true,
"InstanceTenancy": "default",
"Tags": [
{
"Key": "Name",
"Value": "aws-cdk-ec2-vpc-azs/MyVpc"
}
]
}
},
"MyVpcPublicSubnet1SubnetF6608456": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "MyVpcF9F0CA6F"
},
"AvailabilityZone": {
"Fn::Select": [
1,
{
"Fn::GetAZs": ""
}
]
},
"CidrBlock": "10.0.0.0/17",
"MapPublicIpOnLaunch": true,
"Tags": [
{
"Key": "aws-cdk:subnet-name",
"Value": "Public"
},
{
"Key": "aws-cdk:subnet-type",
"Value": "Public"
},
{
"Key": "Name",
"Value": "aws-cdk-ec2-vpc-azs/MyVpc/PublicSubnet1"
}
]
}
},
"MyVpcPublicSubnet1RouteTableC46AB2F4": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "MyVpcF9F0CA6F"
},
"Tags": [
{
"Key": "Name",
"Value": "aws-cdk-ec2-vpc-azs/MyVpc/PublicSubnet1"
}
]
}
},
"MyVpcPublicSubnet1RouteTableAssociation2ECEE1CB": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "MyVpcPublicSubnet1RouteTableC46AB2F4"
},
"SubnetId": {
"Ref": "MyVpcPublicSubnet1SubnetF6608456"
}
}
},
"MyVpcPublicSubnet1DefaultRoute95FDF9EB": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "MyVpcPublicSubnet1RouteTableC46AB2F4"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "MyVpcIGW5C4A4F63"
}
},
"DependsOn": [
"MyVpcVPCGW488ACE0D"
]
},
"MyVpcPublicSubnet1EIP096967CB": {
"Type": "AWS::EC2::EIP",
"Properties": {
"Domain": "vpc",
"Tags": [
{
"Key": "Name",
"Value": "aws-cdk-ec2-vpc-azs/MyVpc/PublicSubnet1"
}
]
}
},
"MyVpcPublicSubnet1NATGatewayAD3400C1": {
"Type": "AWS::EC2::NatGateway",
"Properties": {
"SubnetId": {
"Ref": "MyVpcPublicSubnet1SubnetF6608456"
},
"AllocationId": {
"Fn::GetAtt": [
"MyVpcPublicSubnet1EIP096967CB",
"AllocationId"
]
},
"Tags": [
{
"Key": "Name",
"Value": "aws-cdk-ec2-vpc-azs/MyVpc/PublicSubnet1"
}
]
}
},
"MyVpcPrivateSubnet1Subnet5057CF7E": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "MyVpcF9F0CA6F"
},
"AvailabilityZone": {
"Fn::Select": [
1,
{
"Fn::GetAZs": ""
}
]
},
"CidrBlock": "10.0.128.0/17",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "aws-cdk:subnet-name",
"Value": "Private"
},
{
"Key": "aws-cdk:subnet-type",
"Value": "Private"
},
{
"Key": "Name",
"Value": "aws-cdk-ec2-vpc-azs/MyVpc/PrivateSubnet1"
}
]
}
},
"MyVpcPrivateSubnet1RouteTable8819E6E2": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "MyVpcF9F0CA6F"
},
"Tags": [
{
"Key": "Name",
"Value": "aws-cdk-ec2-vpc-azs/MyVpc/PrivateSubnet1"
}
]
}
},
"MyVpcPrivateSubnet1RouteTableAssociation56D38C7E": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "MyVpcPrivateSubnet1RouteTable8819E6E2"
},
"SubnetId": {
"Ref": "MyVpcPrivateSubnet1Subnet5057CF7E"
}
}
},
"MyVpcPrivateSubnet1DefaultRouteA8CDE2FA": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "MyVpcPrivateSubnet1RouteTable8819E6E2"
},
"DestinationCidrBlock": "0.0.0.0/0",
"NatGatewayId": {
"Ref": "MyVpcPublicSubnet1NATGatewayAD3400C1"
}
}
},
"MyVpcIGW5C4A4F63": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": "aws-cdk-ec2-vpc-azs/MyVpc"
}
]
}
},
"MyVpcVPCGW488ACE0D": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "MyVpcF9F0CA6F"
},
"InternetGatewayId": {
"Ref": "MyVpcIGW5C4A4F63"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"20.0.0"}
14 changes: 14 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/vpc-azs.integ.snapshot/integ.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": "20.0.0",
"testCases": {
"integ.vpc-azs": {
"stacks": [
"aws-cdk-ec2-vpc-azs"
],
"diffAssets": false,
"stackUpdateWorkflow": true
}
},
"synthContext": {},
"enableLookups": false
}
Loading

0 comments on commit e3d3dd4

Please sign in to comment.