diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index d566f545d20dc..1e2b7444e9b95 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -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. + * + * This option overrides `maxAzs`. + * + * @default (a subset of) AZs of the stack + */ + readonly availabilityZones?: string[]; + /** * The number of NAT Gateways/Instances to create. * @@ -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 either specific \'availabilityZones\' or \'maxAzs\' number, 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)'); @@ -1317,10 +1332,13 @@ export class Vpc extends VpcBase { Tags.of(this).add(NAME_TAG, props.vpcName || this.node.path); - this.availabilityZones = stack.availabilityZones; + if (props.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({ diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 1bc1379ebfdfe..f4ff22cc126e4 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -588,6 +588,30 @@ describe('vpc', () => { }); }); + + test('with availabilityZones and maxAzs set, throws error', () => { + const stack = getTestStack(); + expect(() => { + new Vpc(stack, 'VPC', { + availabilityZones: stack.availabilityZones, + maxAzs: 1, + }); + }).toThrow(/Vpc supports either specific 'availabilityZones' or 'maxAzs'/); + }); + + test('with availabilityZones set', () => { + const stack = getTestStack(); + new Vpc(stack, 'VPC', { + availabilityZones: [`${stack.region}b`], + }); + Template.fromStack(stack).resourceCountIs('AWS::EC2::Subnet', 2); + for (let i = 1; i < 2; i++) { + Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { + AvailabilityZone: `${stack.region}b`, + }); + } + }); + test('with natGateway set to 1', () => { const stack = getTestStack(); new Vpc(stack, 'VPC', {