Skip to content

Commit

Permalink
feat(aws-ec2): Add SubnetFilter for Id and CIDR netmask (aws#15373)
Browse files Browse the repository at this point in the history
This PR adds a couple of basic SubnetFilters into the CDK directly so they don't have to be needlessly reimplemented.  The `SubnetIdSubnetFilter` filters subnets by ID and the `CidrMaskSubnetFilter` filters subnets based on the CIDR netmask.

closes aws#15228
----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
ABevier authored and hollanddd committed Aug 26, 2021
1 parent caa674a commit a801ef1
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 2 deletions.
8 changes: 7 additions & 1 deletion packages/@aws-cdk/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ Which subnets are selected is evaluated as follows:
* `onePerAz`: per availability zone, a maximum of one subnet will be returned (Useful for resource
types that do not allow creating two ENIs in the same availability zone).
* `subnetFilters`: additional filtering on subnets using any number of user-provided filters which
extend the SubnetFilter class.
extend `SubnetFilter`. The following methods on the `SubnetFilter` class can be used to create
a filter:
* `byIds`: chooses subnets from a list of ids
* `availabilityZones`: chooses subnets in the provided list of availability zones
* `onePerAz`: chooses at most one subnet per availability zone
* `containsIpAddresses`: chooses a subnet which contains *any* of the listed ip addresses
* `byCidrMask`: chooses subnets that have the provided CIDR netmask

### Using NAT instances

Expand Down
58 changes: 57 additions & 1 deletion packages/@aws-cdk/aws-ec2/lib/subnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import { ISubnet } from './vpc';
*/
export abstract class SubnetFilter {

/**
* Chooses subnets by id.
*/
public static byIds(subnetIds: string[]): SubnetFilter {
return new SubnetIdSubnetFilter(subnetIds);
}

/**
* Chooses subnets which are in one of the given availability zones.
*/
Expand All @@ -29,6 +36,13 @@ export abstract class SubnetFilter {
return new ContainsIpAddressesSubnetFilter(ipv4addrs);
}

/**
* Chooses subnets which have the provided CIDR netmask.
*/
public static byCidrMask(mask: number): SubnetFilter {
return new CidrMaskSubnetFilter(mask);
}

/**
* Executes the subnet filtering logic, returning a filtered set of subnets.
*/
Expand Down Expand Up @@ -112,4 +126,46 @@ class ContainsIpAddressesSubnetFilter extends SubnetFilter {
return cidrBlockObjs.some(cidr => subnetCidrBlock.containsCidr(cidr));
});
}
}
}

/**
* Chooses subnets based on the subnetId
*/
class SubnetIdSubnetFilter extends SubnetFilter {

private readonly subnetIds: string[];

constructor(subnetIds: string[]) {
super();
this.subnetIds = subnetIds;
}

/**
* Executes the subnet filtering logic.
*/
public selectSubnets(subnets: ISubnet[]): ISubnet[] {
return subnets.filter(subnet => this.subnetIds.includes(subnet.subnetId));
}
}

/**
* Chooses subnets based on the CIDR Netmask
*/
class CidrMaskSubnetFilter extends SubnetFilter {
private readonly mask: number

constructor(mask: number) {
super();
this.mask = mask;
}

/**
* Executes the subnet filtering logic.
*/
public selectSubnets(subnets: ISubnet[]): ISubnet[] {
return subnets.filter(subnet => {
const subnetCidr = new CidrBlock(subnet.ipv4CidrBlock);
return subnetCidr.mask === this.mask;
});
}
}
52 changes: 52 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/vpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,58 @@ nodeunitShim({
}));
test.done();
},

'can filter by Subnet Ids'(test: Test) {
// GIVEN
const stack = getTestStack();

const vpc = Vpc.fromVpcAttributes(stack, 'VPC', {
vpcId: 'vpc-1234',
vpcCidrBlock: '192.168.0.0/16',
availabilityZones: ['dummy1a', 'dummy1b', 'dummy1c'],
privateSubnetIds: ['priv-1', 'priv-2', 'priv-3'],
});

// WHEN
new InterfaceVpcEndpoint(stack, 'VPC Endpoint', {
vpc,
service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443),
subnets: {
subnetFilters: [SubnetFilter.byIds(['priv-1', 'priv-2'])],
},
});

// THEN
cdkExpect(stack).to(haveResource('AWS::EC2::VPCEndpoint', {
ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc',
SubnetIds: ['priv-1', 'priv-2'],
}));
test.done();
},

'can filter by Cidr Netmask'(test: Test) {
// GIVEN
const stack = getTestStack();
const vpc = new Vpc(stack, 'VpcNetwork', {
maxAzs: 1,
subnetConfiguration: [
{ name: 'normalSn1', subnetType: SubnetType.PUBLIC, cidrMask: 20 },
{ name: 'normalSn2', subnetType: SubnetType.PUBLIC, cidrMask: 20 },
{ name: 'smallSn', subnetType: SubnetType.PUBLIC, cidrMask: 28 },
],
});

// WHEN
const { subnetIds } = vpc.selectSubnets(
{ subnetFilters: [SubnetFilter.byCidrMask(20)] },
);

// THEN
test.deepEqual(subnetIds.length, 2);
const expected = vpc.publicSubnets.filter(s => s.ipv4CidrBlock.endsWith('/20'));
test.deepEqual(subnetIds, expected.map(s => s.subnetId));
test.done();
},
},
});

Expand Down

0 comments on commit a801ef1

Please sign in to comment.