Skip to content

Commit

Permalink
feat(ec2): support reserving azs space in VPCs
Browse files Browse the repository at this point in the history
  • Loading branch information
Yogesh Chopra authored and yogeshchopra committed Oct 30, 2022
1 parent fadbfc1 commit 6a295b1
Show file tree
Hide file tree
Showing 12 changed files with 1,556 additions and 0 deletions.
25 changes: 25 additions & 0 deletions packages/@aws-cdk/aws-ec2/README.md
Expand Up @@ -273,6 +273,31 @@ new ec2.Vpc(stack, 'TheVPC', {

With this method of IP address management, no attempt is made to guess at subnet group sizes or to exhaustively allocate the IP range. All subnet groups must have an explicit `cidrMask` set as part of their subnet configuration, or `defaultSubnetIpv4NetmaskLength` must be set for a default size. If not, synthesis will fail and you must provide one or the other.

### Reserving availability zones

There are situations where the IP space for availability zones will
need to be reserved. This is useful in situations where availability
zones would need to be added after the vpc is originally deployed,
without causing IP renumbering for availability zones subnets. The IP
space for reserving `n` availability zones can be done by setting the
`reservedAzs` to `n` in vpc props, as shown below:

```ts
const vpc = new ec2.Vpc(this, 'TheVPC', {
cidr: '10.0.0.0/21',
maxAzs: 3,
reservedAzs: 1,
});
```

In the example above, the subnets for reserved availability zones is not
actually provisioned but its IP space is still reserved. If, in the future,
new availability zones needs to be provisioned, then we would decrement
the value of `reservedAzs` and increment the `maxAzs` or `availabilityZones`
accordingly. This action would not cause the IP address of subnets to get
renumbered, but rather the IP space that was previously reserved will be
used for the new availability zones subnets.

### Advanced Subnet Configuration

If the default VPC configuration (public and private subnets spanning the
Expand Down
18 changes: 18 additions & 0 deletions packages/@aws-cdk/aws-ec2/lib/vpc.ts
Expand Up @@ -21,6 +21,7 @@ import { VpcLookupOptions } from './vpc-lookup';
import { EnableVpnGatewayOptions, VpnConnection, VpnConnectionOptions, VpnConnectionType, VpnGateway } from './vpn';

const VPC_SUBNET_SYMBOL = Symbol.for('@aws-cdk/aws-ec2.VpcSubnet');
const FAKE_AZ_NAME = 'fake-az';

export interface ISubnet extends IResource {
/**
Expand Down Expand Up @@ -888,6 +889,16 @@ export interface VpcProps {
*/
readonly maxAzs?: number;

/**
* Define the number of AZs to reserve.
*
* When specified, the IP space is reserved for the azs but no actual
* resources are provisioned.
*
* @default 0
*/
readonly reservedAzs?: number;

/**
* Availability zones this VPC spans.
*
Expand Down Expand Up @@ -1396,6 +1407,9 @@ export class Vpc extends VpcBase {
const maxAZs = props.maxAzs ?? 3;
this.availabilityZones = stack.availabilityZones.slice(0, maxAZs);
}
for (let i = 0; props.reservedAzs && i < props.reservedAzs; i++) {
this.availabilityZones.push(FAKE_AZ_NAME);
}


this.vpcId = this.resource.ref;
Expand Down Expand Up @@ -1561,6 +1575,10 @@ export class Vpc extends VpcBase {
// For reserved subnets, do not create any resources
return;
}
if (availabilityZone === FAKE_AZ_NAME) {
// For reserved azs, do not create any resources
return;
}

// mapPublicIpOnLaunch true in Subnet.Public, false in Subnet.Private or Subnet.Isolated.
let mapPublicIpOnLaunch = false;
Expand Down
15 changes: 15 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/integ.vpc-reserved-azs.ts
@@ -0,0 +1,15 @@
import * as cdk from '@aws-cdk/core';
import { IntegTest } from '@aws-cdk/integ-tests';
import * as ec2 from '../lib';

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

new ec2.Vpc(stack, 'MyVpc', {
reservedAzs: 2,
maxAzs: 3,
});

new IntegTest(app, 'vpc-reserved-azs', {
testCases: [stack],
});
@@ -0,0 +1 @@
{"version":"21.0.0"}
@@ -0,0 +1,12 @@
{
"version": "21.0.0",
"testCases": {
"vpc-reserved-azs/DefaultTest": {
"stacks": [
"integtest-vpc-reserved-azs"
],
"assertionStack": "vpc-reserved-azs/DefaultTest/DeployAssert",
"assertionStackName": "vpcreservedazsDefaultTestDeployAssertE48D2C6D"
}
}
}
@@ -0,0 +1,19 @@
{
"version": "21.0.0",
"files": {
"2316c1d0bd29529a3dc0b6ffcefa3aa88c8d79ea1b90aff8056d49f0de23e53b": {
"source": {
"path": "integtest-vpc-reserved-azs.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "2316c1d0bd29529a3dc0b6ffcefa3aa88c8d79ea1b90aff8056d49f0de23e53b.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
}
},
"dockerImages": {}
}

0 comments on commit 6a295b1

Please sign in to comment.