Skip to content

Commit 2762c60

Browse files
committed
feat(ec2): subnet ipv4 cidr blocks on imported vpc
When using `Vpc.fromVpcAttributes()` to import a VPC, it is possible to specify all subnet properties except for the IPv4 CIDR block. This means that any attempt to read the `ipv4CidrBlock` property of a subnet on such a VPC will throw with the message: > You cannot reference an imported Subnet's IPv4 CIDR if it was not supplied. Add the ipv4CidrBlock when importing using Subnet.fromSubnetAttributes() This commit extends the `VpcAttributes` interface to allow for subnet IPv4 CIDR blocks to be passed in alongside the IDs, names and route table IDs for each subnet group (public, private, isolated).
1 parent b66b0ca commit 2762c60

File tree

3 files changed

+79
-4
lines changed

3 files changed

+79
-4
lines changed

packages/@aws-cdk/aws-ec2/lib/util.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,24 @@ export class ImportSubnetGroup {
4646
private readonly subnetIds: string[];
4747
private readonly names: string[];
4848
private readonly routeTableIds: string[];
49+
private readonly ipv4CidrBlocks: string[];
4950
private readonly groups: number;
5051

5152
constructor(
5253
subnetIds: string[] | undefined,
5354
names: string[] | undefined,
5455
routeTableIds: string[] | undefined,
56+
ipv4CidrBlocks: string[] | undefined,
5557
type: SubnetType,
5658
private readonly availabilityZones: string[],
5759
idField: string,
5860
nameField: string,
59-
routeTableIdField: string) {
61+
routeTableIdField: string,
62+
ipv4CidrBlockField: string) {
6063

6164
this.subnetIds = subnetIds || [];
6265
this.routeTableIds = routeTableIds || [];
66+
this.ipv4CidrBlocks = ipv4CidrBlocks || [];
6367
this.groups = this.subnetIds.length / this.availabilityZones.length;
6468

6569
if (Math.floor(this.groups) !== this.groups) {
@@ -71,6 +75,11 @@ export class ImportSubnetGroup {
7175
/* eslint-disable max-len */
7276
throw new Error(`Number of ${routeTableIdField} (${this.routeTableIds.length}) must be equal to the amount of ${idField} (${this.subnetIds.length}).`);
7377
}
78+
if (this.ipv4CidrBlocks.length !== this.subnetIds.length && ipv4CidrBlocks != null) {
79+
// We don't err if no ipv4CidrBlocks were provided to maintain backwards-compatibility. See https://github.com/aws/aws-cdk/pull/3171
80+
/* eslint-disable max-len */
81+
throw new Error(`Number of ${ipv4CidrBlockField} (${this.ipv4CidrBlocks.length}) must be equal to the amount of ${idField} (${this.subnetIds.length}).`);
82+
}
7483

7584
this.names = this.normalizeNames(names, defaultSubnetName(type), nameField);
7685
}
@@ -82,6 +91,7 @@ export class ImportSubnetGroup {
8291
availabilityZone: this.pickAZ(i),
8392
subnetId: this.subnetIds[i],
8493
routeTableId: this.routeTableIds[i],
94+
ipv4CidrBlock: this.ipv4CidrBlocks[i],
8595
});
8696
});
8797
}

packages/@aws-cdk/aws-ec2/lib/vpc.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,15 @@ export interface VpcAttributes {
718718
*/
719719
readonly publicSubnetRouteTableIds?: string[];
720720

721+
/**
722+
* List of IPv4 CIDR blocks for the public subnets.
723+
*
724+
* Must be undefined or have an entry for every public subnet group.
725+
*
726+
* @default - Retrieving the CIDR from a public subnet will fail
727+
*/
728+
readonly publicSubnetIpv4CidrBlocks?: string[];
729+
721730
/**
722731
* List of private subnet IDs
723732
*
@@ -739,6 +748,15 @@ export interface VpcAttributes {
739748
*/
740749
readonly privateSubnetRouteTableIds?: string[];
741750

751+
/**
752+
* List of IPv4 CIDR blocks for the private subnets.
753+
*
754+
* Must be undefined or have an entry for every private subnet group.
755+
*
756+
* @default - Retrieving the CIDR from a private subnet will fail
757+
*/
758+
readonly privateSubnetIpv4CidrBlocks?: string[];
759+
742760
/**
743761
* List of isolated subnet IDs
744762
*
@@ -760,6 +778,15 @@ export interface VpcAttributes {
760778
*/
761779
readonly isolatedSubnetRouteTableIds?: string[];
762780

781+
/**
782+
* List of IPv4 CIDR blocks for the isolated subnets.
783+
*
784+
* Must be undefined or have an entry for every isolated subnet group.
785+
*
786+
* @default - Retrieving the CIDR from an isolated subnet will fail
787+
*/
788+
readonly isolatedSubnetIpv4CidrBlocks?: string[];
789+
763790
/**
764791
* VPN gateway's identifier
765792
*/
@@ -2084,9 +2111,9 @@ class ImportedVpc extends VpcBase {
20842111
}
20852112

20862113
/* eslint-disable max-len */
2087-
const pub = new ImportSubnetGroup(props.publicSubnetIds, props.publicSubnetNames, props.publicSubnetRouteTableIds, SubnetType.PUBLIC, this.availabilityZones, 'publicSubnetIds', 'publicSubnetNames', 'publicSubnetRouteTableIds');
2088-
const priv = new ImportSubnetGroup(props.privateSubnetIds, props.privateSubnetNames, props.privateSubnetRouteTableIds, SubnetType.PRIVATE_WITH_EGRESS, this.availabilityZones, 'privateSubnetIds', 'privateSubnetNames', 'privateSubnetRouteTableIds');
2089-
const iso = new ImportSubnetGroup(props.isolatedSubnetIds, props.isolatedSubnetNames, props.isolatedSubnetRouteTableIds, SubnetType.PRIVATE_ISOLATED, this.availabilityZones, 'isolatedSubnetIds', 'isolatedSubnetNames', 'isolatedSubnetRouteTableIds');
2114+
const pub = new ImportSubnetGroup(props.publicSubnetIds, props.publicSubnetNames, props.publicSubnetRouteTableIds, props.publicSubnetIpv4CidrBlocks, SubnetType.PUBLIC, this.availabilityZones, 'publicSubnetIds', 'publicSubnetNames', 'publicSubnetRouteTableIds', 'ipv4CidrBlocks');
2115+
const priv = new ImportSubnetGroup(props.privateSubnetIds, props.privateSubnetNames, props.privateSubnetRouteTableIds, props.privateSubnetIpv4CidrBlocks, SubnetType.PRIVATE_WITH_EGRESS, this.availabilityZones, 'privateSubnetIds', 'privateSubnetNames', 'privateSubnetRouteTableIds', 'ipv4CidrBlocks');
2116+
const iso = new ImportSubnetGroup(props.isolatedSubnetIds, props.isolatedSubnetNames, props.isolatedSubnetRouteTableIds, props.isolatedSubnetIpv4CidrBlocks, SubnetType.PRIVATE_ISOLATED, this.availabilityZones, 'isolatedSubnetIds', 'isolatedSubnetNames', 'isolatedSubnetRouteTableIds', 'ipv4CidrBlocks');
20902117
/* eslint-enable max-len */
20912118

20922119
this.publicSubnets = pub.import(this);

packages/@aws-cdk/aws-ec2/test/vpc.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,44 @@ describe('vpc', () => {
16761676

16771677
});
16781678

1679+
test('subnet IPv4 CIDR blocks are available on imported subnets', () => {
1680+
// GIVEN
1681+
const stack = new Stack();
1682+
const vpc = Vpc.fromVpcAttributes(stack, 'VPC', {
1683+
vpcId: 'vpc-1234',
1684+
availabilityZones: ['dummy1a', 'dummy1b', 'dummy1c'],
1685+
publicSubnetIds: ['pub-1', 'pub-2', 'pub-3'],
1686+
publicSubnetIpv4CidrBlocks: ['10.0.0.0/18', '10.0.64.0/18', '10.0.128.0/18'],
1687+
privateSubnetIds: ['pri-1', 'pri-2', 'pri-3'],
1688+
privateSubnetIpv4CidrBlocks: ['10.10.0.0/18', '10.10.64.0/18', '10.10.128.0/18'],
1689+
isolatedSubnetIds: ['iso-1', 'iso-2', 'iso-3'],
1690+
isolatedSubnetIpv4CidrBlocks: ['10.20.0.0/18', '10.20.64.0/18', '10.20.128.0/18'],
1691+
});
1692+
1693+
// WHEN
1694+
const public1 = vpc.publicSubnets.find(({ subnetId }) => subnetId === 'pub-1');
1695+
const public2 = vpc.publicSubnets.find(({ subnetId }) => subnetId === 'pub-2');
1696+
const public3 = vpc.publicSubnets.find(({ subnetId }) => subnetId === 'pub-3');
1697+
const private1 = vpc.privateSubnets.find(({ subnetId }) => subnetId === 'pri-1');
1698+
const private2 = vpc.privateSubnets.find(({ subnetId }) => subnetId === 'pri-2');
1699+
const private3 = vpc.privateSubnets.find(({ subnetId }) => subnetId === 'pri-3');
1700+
const isolated1 = vpc.isolatedSubnets.find(({ subnetId }) => subnetId === 'iso-1');
1701+
const isolated2 = vpc.isolatedSubnets.find(({ subnetId }) => subnetId === 'iso-2');
1702+
const isolated3 = vpc.isolatedSubnets.find(({ subnetId }) => subnetId === 'iso-3');
1703+
1704+
// THEN
1705+
expect(public1?.ipv4CidrBlock).toEqual('10.0.0.0/18');
1706+
expect(public2?.ipv4CidrBlock).toEqual('10.0.64.0/18');
1707+
expect(public3?.ipv4CidrBlock).toEqual('10.0.128.0/18');
1708+
expect(private1?.ipv4CidrBlock).toEqual('10.10.0.0/18');
1709+
expect(private2?.ipv4CidrBlock).toEqual('10.10.64.0/18');
1710+
expect(private3?.ipv4CidrBlock).toEqual('10.10.128.0/18');
1711+
expect(isolated1?.ipv4CidrBlock).toEqual('10.20.0.0/18');
1712+
expect(isolated2?.ipv4CidrBlock).toEqual('10.20.64.0/18');
1713+
expect(isolated3?.ipv4CidrBlock).toEqual('10.20.128.0/18');
1714+
1715+
});
1716+
16791717
test('selecting subnets by name fails if the name is unknown', () => {
16801718
// GIVEN
16811719
const stack = new Stack();

0 commit comments

Comments
 (0)