From 61c6f9634dec3945d9a272d40db5d55dda222086 Mon Sep 17 00:00:00 2001 From: James Fleming Date: Tue, 1 Sep 2020 18:48:32 +0000 Subject: [PATCH 01/14] Introduce subnet selector, didn't break any tests yet --- packages/@aws-cdk/aws-ec2/lib/index.ts | 1 + packages/@aws-cdk/aws-ec2/lib/subnet.ts | 57 +++++++++++++++++++++++++ packages/@aws-cdk/aws-ec2/lib/vpc.ts | 23 ++++++++++ 3 files changed, 81 insertions(+) create mode 100644 packages/@aws-cdk/aws-ec2/lib/subnet.ts diff --git a/packages/@aws-cdk/aws-ec2/lib/index.ts b/packages/@aws-cdk/aws-ec2/lib/index.ts index ff7f7131d53e4..ca25a02f3f8d1 100644 --- a/packages/@aws-cdk/aws-ec2/lib/index.ts +++ b/packages/@aws-cdk/aws-ec2/lib/index.ts @@ -10,6 +10,7 @@ export * from './network-acl'; export * from './network-acl-types'; export * from './port'; export * from './security-group'; +export * from './subnet'; export * from './peer'; export * from './volume'; export * from './vpc'; diff --git a/packages/@aws-cdk/aws-ec2/lib/subnet.ts b/packages/@aws-cdk/aws-ec2/lib/subnet.ts new file mode 100644 index 0000000000000..4bc182a4b0896 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/lib/subnet.ts @@ -0,0 +1,57 @@ +import { ISubnet } from './vpc'; + +/** + * Contains logic which chooses a set of subnets from a larger list, in conjunction + * with SubnetSelection for determining where to place AWS resources such as VPC + * endpoints, EC2 instances, etc. + */ +export interface ISubnetSelector { + + /** + * Executes the subnet filtering logic. + */ + selectSubnets(subnets: ISubnet[]): ISubnet[]; +} + +/** + * Filters out subnets which are not in one of the provided availability zones. + */ +export class AvailabilityZoneSubnetSelector implements ISubnetSelector { + + private readonly availabilityZones: string[]; + + constructor(availabilityZones: string[]) { + this.availabilityZones = availabilityZones; + } + + /** + * Executes the subnet filtering logic. + */ + public selectSubnets(subnets: ISubnet[]): ISubnet[] { + return subnets.filter(s => this.availabilityZones.includes(s.availabilityZone)); + } +} + +/** + * Filters out subnets such that there is at most one per availability zone. + */ +export class OnePerAZSubnetSelector implements ISubnetSelector { + + constructor() {} + + /** + * Executes the subnet filtering logic. + */ + public selectSubnets(subnets: ISubnet[]): ISubnet[] { + return this.retainOnePerAz(subnets); + } + + private retainOnePerAz(subnets: ISubnet[]): ISubnet[] { + const azsSeen = new Set(); + return subnets.filter(subnet => { + if (azsSeen.has(subnet.availabilityZone)) { return false; } + azsSeen.add(subnet.availabilityZone); + return true; + }); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index c0b65abee39df..ee323835e1256 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -11,6 +11,7 @@ import { import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; import { NetworkBuilder } from './network-util'; +import { AvailabilityZoneSubnetSelector, OnePerAZSubnetSelector, ISubnetSelector } from './subnet'; import { allRouteTableIds, defaultSubnetName, flatten, ImportSubnetGroup, subnetGroupNameFromConstructId, subnetId } from './util'; import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, GatewayVpcEndpointOptions, InterfaceVpcEndpoint, InterfaceVpcEndpointOptions } from './vpc-endpoint'; import { FlowLog, FlowLogOptions, FlowLogResourceType } from './vpc-flow-logs'; @@ -236,6 +237,13 @@ export interface SubnetSelection { */ readonly onePerAz?: boolean; + /** + * List of provided subnet filters. + * + * @default - none + */ + readonly subnetFilters?: ISubnetSelector[]; + /** * Explicitly select individual subnets * @@ -460,17 +468,32 @@ abstract class VpcBase extends Resource implements IVpc { subnets = this.selectSubnetObjectsByType(type); } + let subnetFilters = selection.subnetFilters ?? []; + if (selection.availabilityZones !== undefined) { // Filter by AZs, if specified + subnetFilters.push(new AvailabilityZoneSubnetSelector(selection.availabilityZones)); subnets = retainByAZ(subnets, selection.availabilityZones); } if (!!selection.onePerAz && subnets.length > 0) { // Ensure one per AZ if specified + subnetFilters.push(new OnePerAZSubnetSelector()); subnets = retainOnePerAz(subnets); } + subnets = this.applySubnetFilters(subnets, subnetFilters); + return subnets; } + private applySubnetFilters(subnets: ISubnet[], filters: ISubnetSelector[]): ISubnet[] { + let filtered = subnets; + // Apply each filter in sequence + for (const filter of filters) { + filtered = filter.selectSubnets(filtered); + } + return filtered; + } + private selectSubnetObjectsByName(groupName: string) { const allSubnets = [...this.publicSubnets, ...this.privateSubnets, ...this.isolatedSubnets]; const subnets = allSubnets.filter(s => subnetGroupNameFromConstructId(s) === groupName); From 638ec87de80ed1e3e3f30716aafbad7ba3b9df80 Mon Sep 17 00:00:00 2001 From: James Fleming Date: Tue, 1 Sep 2020 19:04:07 +0000 Subject: [PATCH 02/14] Move availability zone and onePerAz over to using the selector, no tests broken yet --- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index ee323835e1256..df04180a8924c 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -472,12 +472,10 @@ abstract class VpcBase extends Resource implements IVpc { if (selection.availabilityZones !== undefined) { // Filter by AZs, if specified subnetFilters.push(new AvailabilityZoneSubnetSelector(selection.availabilityZones)); - subnets = retainByAZ(subnets, selection.availabilityZones); } if (!!selection.onePerAz && subnets.length > 0) { // Ensure one per AZ if specified subnetFilters.push(new OnePerAZSubnetSelector()); - subnets = retainOnePerAz(subnets); } subnets = this.applySubnetFilters(subnets, subnetFilters); @@ -573,19 +571,6 @@ abstract class VpcBase extends Resource implements IVpc { } } -function retainByAZ(subnets: ISubnet[], azs: string[]): ISubnet[] { - return subnets.filter(s => azs.includes(s.availabilityZone)); -} - -function retainOnePerAz(subnets: ISubnet[]): ISubnet[] { - const azsSeen = new Set(); - return subnets.filter(subnet => { - if (azsSeen.has(subnet.availabilityZone)) { return false; } - azsSeen.add(subnet.availabilityZone); - return true; - }); -} - /** * Properties that reference an external Vpc */ From c1cd7c0a9c12f9afe49936e3e1070dc565033237 Mon Sep 17 00:00:00 2001 From: James Fleming Date: Tue, 1 Sep 2020 22:09:21 +0000 Subject: [PATCH 03/14] Minor refactoring --- packages/@aws-cdk/aws-ec2/lib/subnet.ts | 2 +- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 57 +++++++++++++------------ 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/subnet.ts b/packages/@aws-cdk/aws-ec2/lib/subnet.ts index 4bc182a4b0896..13b6a6d7be5f8 100644 --- a/packages/@aws-cdk/aws-ec2/lib/subnet.ts +++ b/packages/@aws-cdk/aws-ec2/lib/subnet.ts @@ -54,4 +54,4 @@ export class OnePerAZSubnetSelector implements ISubnetSelector { return true; }); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index df04180a8924c..a4cebadd7bc31 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -1,7 +1,7 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { - ConcreteDependable, Construct, ContextProvider, DependableTrait, IConstruct, - IDependable, IResource, Lazy, Resource, Stack, Token, Tags, + Annotations, ConcreteDependable, Construct, ContextProvider, DependableTrait, + IConstruct, IDependable, IResource, Lazy, Resource, Stack, Token, Tags, } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { @@ -468,17 +468,8 @@ abstract class VpcBase extends Resource implements IVpc { subnets = this.selectSubnetObjectsByType(type); } - let subnetFilters = selection.subnetFilters ?? []; - - if (selection.availabilityZones !== undefined) { // Filter by AZs, if specified - subnetFilters.push(new AvailabilityZoneSubnetSelector(selection.availabilityZones)); - } - - if (!!selection.onePerAz && subnets.length > 0) { // Ensure one per AZ if specified - subnetFilters.push(new OnePerAZSubnetSelector()); - } - - subnets = this.applySubnetFilters(subnets, subnetFilters); + // Apply all the filters + subnets = this.applySubnetFilters(subnets, selection.subnetFilters ?? []); return subnets; } @@ -531,9 +522,26 @@ abstract class VpcBase extends Resource implements IVpc { * PUBLIC (in that order) that has any subnets. */ private reifySelectionDefaults(placement: SubnetSelection): SubnetSelection { + + // Establish which subnet filters are going to be used + let subnetFilters = placement.subnetFilters ?? []; + + // Backwards compatibility with existing `availabilityZones` and `onePerAz` functionality + if (placement.availabilityZones !== undefined) { // Filter by AZs, if specified + subnetFilters.push(new AvailabilityZoneSubnetSelector(placement.availabilityZones)); + } + if (!!placement.onePerAz) { // Ensure one per AZ if specified + subnetFilters.push(new OnePerAZSubnetSelector()); + } + + // Overwrite the provided placement filters + placement = { ...placement, subnetFilters: subnetFilters }; + if (placement.subnetName !== undefined) { if (placement.subnetGroupName !== undefined) { throw new Error('Please use only \'subnetGroupName\' (\'subnetName\' is deprecated and has the same behavior)'); + } else { + Annotations.of(this).addWarning('Usage of \'subnetName\' in SubnetSelection is deprecated, use \'subnetGroupName\' instead'); } placement = { ...placement, subnetGroupName: placement.subnetName }; } @@ -545,25 +553,18 @@ abstract class VpcBase extends Resource implements IVpc { } if (placement.subnetType === undefined && placement.subnetGroupName === undefined && placement.subnets === undefined) { + let subnetType; // Return default subnet type based on subnets that actually exist if (this.privateSubnets.length > 0) { - return { - subnetType: SubnetType.PRIVATE, - onePerAz: placement.onePerAz, - availabilityZones: placement.availabilityZones, - }; - } - if (this.isolatedSubnets.length > 0) { - return { - subnetType: SubnetType.ISOLATED, - onePerAz: placement.onePerAz, - availabilityZones: placement.availabilityZones, - }; + subnetType = SubnetType.PRIVATE; + } else if (this.isolatedSubnets.length > 0) { + subnetType = SubnetType.ISOLATED; + } else { + subnetType = SubnetType.PUBLIC; } return { - subnetType: SubnetType.PUBLIC, - onePerAz: placement.onePerAz, - availabilityZones: placement.availabilityZones, + subnetType: subnetType, + subnetFilters: placement.subnetFilters, }; } From 8ba3b7b4829397c311c1488e162bcbdeb92f3d50 Mon Sep 17 00:00:00 2001 From: James Fleming Date: Wed, 2 Sep 2020 00:12:39 +0000 Subject: [PATCH 04/14] Refactoring and rewording --- packages/@aws-cdk/aws-ec2/lib/subnet.ts | 8 ++++---- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 14 ++------------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/subnet.ts b/packages/@aws-cdk/aws-ec2/lib/subnet.ts index 13b6a6d7be5f8..aa6dc717134c6 100644 --- a/packages/@aws-cdk/aws-ec2/lib/subnet.ts +++ b/packages/@aws-cdk/aws-ec2/lib/subnet.ts @@ -2,19 +2,19 @@ import { ISubnet } from './vpc'; /** * Contains logic which chooses a set of subnets from a larger list, in conjunction - * with SubnetSelection for determining where to place AWS resources such as VPC + * with SubnetSelection, to determine where to place AWS resources such as VPC * endpoints, EC2 instances, etc. */ export interface ISubnetSelector { /** - * Executes the subnet filtering logic. + * Executes the subnet filtering logic, returning a filtered set of subnets. */ selectSubnets(subnets: ISubnet[]): ISubnet[]; } /** - * Filters out subnets which are not in one of the provided availability zones. + * Chooses subnets which are in one of the given availability zones. */ export class AvailabilityZoneSubnetSelector implements ISubnetSelector { @@ -33,7 +33,7 @@ export class AvailabilityZoneSubnetSelector implements ISubnetSelector { } /** - * Filters out subnets such that there is at most one per availability zone. + * Chooses subnets such that there is at most one per availability zone. */ export class OnePerAZSubnetSelector implements ISubnetSelector { diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index a4cebadd7bc31..cc0539ded6650 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -553,19 +553,9 @@ abstract class VpcBase extends Resource implements IVpc { } if (placement.subnetType === undefined && placement.subnetGroupName === undefined && placement.subnets === undefined) { - let subnetType; // Return default subnet type based on subnets that actually exist - if (this.privateSubnets.length > 0) { - subnetType = SubnetType.PRIVATE; - } else if (this.isolatedSubnets.length > 0) { - subnetType = SubnetType.ISOLATED; - } else { - subnetType = SubnetType.PUBLIC; - } - return { - subnetType: subnetType, - subnetFilters: placement.subnetFilters, - }; + let subnetType = this.privateSubnets.length ? SubnetType.PRIVATE : this.isolatedSubnets.length ? SubnetType.ISOLATED : SubnetType.PUBLIC; + placement = { ...placement, subnetType: subnetType }; } return placement; From 48d6b565d29f569d72d5213a8bde6b6883842843 Mon Sep 17 00:00:00 2001 From: James Fleming Date: Wed, 2 Sep 2020 00:38:31 +0000 Subject: [PATCH 05/14] re-order logic to be more like original - subnet name/type first, then additional filters --- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index cc0539ded6650..645138cf3175a 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -523,20 +523,6 @@ abstract class VpcBase extends Resource implements IVpc { */ private reifySelectionDefaults(placement: SubnetSelection): SubnetSelection { - // Establish which subnet filters are going to be used - let subnetFilters = placement.subnetFilters ?? []; - - // Backwards compatibility with existing `availabilityZones` and `onePerAz` functionality - if (placement.availabilityZones !== undefined) { // Filter by AZs, if specified - subnetFilters.push(new AvailabilityZoneSubnetSelector(placement.availabilityZones)); - } - if (!!placement.onePerAz) { // Ensure one per AZ if specified - subnetFilters.push(new OnePerAZSubnetSelector()); - } - - // Overwrite the provided placement filters - placement = { ...placement, subnetFilters: subnetFilters }; - if (placement.subnetName !== undefined) { if (placement.subnetGroupName !== undefined) { throw new Error('Please use only \'subnetGroupName\' (\'subnetName\' is deprecated and has the same behavior)'); @@ -558,6 +544,20 @@ abstract class VpcBase extends Resource implements IVpc { placement = { ...placement, subnetType: subnetType }; } + // Establish which subnet filters are going to be used + let subnetFilters = placement.subnetFilters ?? []; + + // Backwards compatibility with existing `availabilityZones` and `onePerAz` functionality + if (placement.availabilityZones !== undefined) { // Filter by AZs, if specified + subnetFilters.push(new AvailabilityZoneSubnetSelector(placement.availabilityZones)); + } + if (!!placement.onePerAz) { // Ensure one per AZ if specified + subnetFilters.push(new OnePerAZSubnetSelector()); + } + + // Overwrite the provided placement filters + placement = { ...placement, subnetFilters: subnetFilters }; + return placement; } } From 9286b0e5dffe606ced9a5190af36105258d93094 Mon Sep 17 00:00:00 2001 From: James Fleming Date: Wed, 2 Sep 2020 01:40:47 +0000 Subject: [PATCH 06/14] Add subnet selection by IP --- packages/@aws-cdk/aws-ec2/lib/subnet.ts | 31 +++++++++ packages/@aws-cdk/aws-ec2/lib/vpc.ts | 33 +++++++++- packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 74 +++++++++++++++++++++- 3 files changed, 133 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/subnet.ts b/packages/@aws-cdk/aws-ec2/lib/subnet.ts index aa6dc717134c6..f51c7e7d13ae0 100644 --- a/packages/@aws-cdk/aws-ec2/lib/subnet.ts +++ b/packages/@aws-cdk/aws-ec2/lib/subnet.ts @@ -1,3 +1,4 @@ +import { CidrBlock, NetworkUtils } from './network-util'; import { ISubnet } from './vpc'; /** @@ -55,3 +56,33 @@ export class OnePerAZSubnetSelector implements ISubnetSelector { }); } } + +/** + * Chooses subnets which contain any of the specified IP addresses. + */ +export class ContainsIpAddressesSubnetSelector implements ISubnetSelector { + + private readonly ipAddresses: string[]; + + constructor(ipAddresses: string[]) { + this.ipAddresses = ipAddresses; + } + + /** + * Executes the subnet filtering logic. + */ + public selectSubnets(subnets: ISubnet[]): ISubnet[] { + return this.retainByIp(subnets, this.ipAddresses); + } + + private retainByIp(subnets: ISubnet[], ips: string[]): ISubnet[] { + const cidrBlockObjs = ips.map(ip => { + const ipNum = NetworkUtils.ipToNum(ip); + return new CidrBlock(ipNum, 32); + }); + return subnets.filter(s => { + const subnetCidrBlock = new CidrBlock(s.ipv4CidrBlock); + return cidrBlockObjs.some(cidr => subnetCidrBlock.containsCidr(cidr)); + }); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 645138cf3175a..662c196e17c16 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -37,6 +37,11 @@ export interface ISubnet extends IResource { */ readonly internetConnectivityEstablished: IDependable; + /** + * The IPv4 CIDR block for this subnet + */ + readonly ipv4CidrBlock: string; + /** * The route table for this subnet */ @@ -653,6 +658,7 @@ export interface VpcAttributes { } export interface SubnetAttributes { + /** * The Availability Zone the subnet is located in * @@ -661,9 +667,11 @@ export interface SubnetAttributes { readonly availabilityZone?: string; /** - * The subnetId for this particular subnet + * The IPv4 CIDR block associated with the subnet + * + * @default - No CIDR information, cannot use CIDR filter features */ - readonly subnetId: string; + readonly ipv4CidrBlock?: string; /** * The ID of the route table for this particular subnet @@ -671,6 +679,11 @@ export interface SubnetAttributes { * @default - No route table information, cannot create VPC endpoints */ readonly routeTableId?: string; + + /** + * The subnetId for this particular subnet + */ + readonly subnetId: string; } /** @@ -1441,6 +1454,11 @@ export class Subnet extends Resource implements ISubnet { */ public readonly availabilityZone: string; + /** + * @attribute + */ + public readonly ipv4CidrBlock: string; + /** * The subnetId for this particular subnet */ @@ -1490,6 +1508,7 @@ export class Subnet extends Resource implements ISubnet { Tags.of(this).add(NAME_TAG, this.node.path); this.availabilityZone = props.availabilityZone; + this.ipv4CidrBlock = props.cidrBlock; const subnet = new CfnSubnet(this, 'Subnet', { vpcId: props.vpcId, cidrBlock: props.cidrBlock, @@ -1889,6 +1908,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public readonly subnetId: string; public readonly routeTable: IRouteTable; private readonly _availabilityZone?: string; + private readonly _ipv4CidrBlock?: string; constructor(scope: Construct, id: string, attrs: SubnetAttributes) { super(scope, id); @@ -1901,6 +1921,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat scope.node.addWarning(`No routeTableId was provided to the subnet ${ref}. Attempting to read its .routeTable.routeTableId will return null/undefined. (More info: https://github.com/aws/aws-cdk/pull/3171)`); } + this._ipv4CidrBlock = attrs.ipv4CidrBlock; this._availabilityZone = attrs.availabilityZone; this.subnetId = attrs.subnetId; this.routeTable = { @@ -1917,6 +1938,14 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat return this._availabilityZone; } + public get ipv4CidrBlock(): string { + if (!this._ipv4CidrBlock) { + // tslint:disable-next-line: max-line-length + throw new Error("You cannot reference an imported Subnet's IPv4 CIDR if it was not supplied. Add the ipv4CidrBlock when importing using Subnet.fromSubnetAttributes()"); + } + return this._ipv4CidrBlock; + } + public associateNetworkAcl(id: string, networkAcl: INetworkAcl): void { const scope = Construct.isConstruct(networkAcl) ? networkAcl : this; const other = Construct.isConstruct(networkAcl) ? this : networkAcl; diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 87752fef51bdb..1df7904907f91 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -2,9 +2,9 @@ import { countResources, expect, haveResource, haveResourceLike, isSuperObject, import { CfnOutput, Lazy, Stack, Tags } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { - AclCidr, AclTraffic, CfnSubnet, CfnVPC, DefaultInstanceTenancy, GenericLinuxImage, InstanceType, InterfaceVpcEndpoint, - InterfaceVpcEndpointService, NatProvider, NetworkAcl, NetworkAclEntry, Peer, Port, PrivateSubnet, PublicSubnet, - RouterType, Subnet, SubnetType, TrafficDirection, Vpc, + AclCidr, AclTraffic, BastionHostLinux, CfnSubnet, CfnVPC, ContainsIpAddressesSubnetSelector, DefaultInstanceTenancy, GenericLinuxImage, + InstanceType, InterfaceVpcEndpoint, InterfaceVpcEndpointService, NatProvider, NetworkAcl, NetworkAclEntry, Peer, Port, PrivateSubnet, + PublicSubnet, RouterType, Subnet, SubnetType, TrafficDirection, Vpc, } from '../lib'; nodeunitShim({ @@ -1381,6 +1381,74 @@ nodeunitShim({ })); test.done(); }, + + 'can filter by single IP address'(test: Test) { + // GIVEN + const stack = getTestStack(); + + // IP space is split into 6 pieces, one public/one private per AZ + const vpc = new Vpc(stack, 'VPC', { + cidr: '10.0.0.0/16', + maxAzs: 3, + }); + + // WHEN + // We want to place this bastion host in the same subnet as this IPv4 + // address. + new BastionHostLinux(stack, 'Bastion', { + vpc, + subnetSelection: { + subnetFilters: [new ContainsIpAddressesSubnetSelector(['10.0.160.0'])], + }, + }); + + // THEN + // 10.0.160.0/19 is the third subnet, sequentially, if you split + // 10.0.0.0/16 into 6 pieces + expect(stack).to(haveResource('AWS::EC2::Instance', { + SubnetId: { + Ref: 'VPCPrivateSubnet3Subnet3EDCD457', + }, + })); + test.done(); + }, + + 'can filter by multiple IP addresses'(test: Test) { + // GIVEN + const stack = getTestStack(); + + // IP space is split into 6 pieces, one public/one private per AZ + const vpc = new Vpc(stack, 'VPC', { + cidr: '10.0.0.0/16', + maxAzs: 3, + }); + + // WHEN + // We want to place this endpoint in the same subnets as these IPv4 + // address. + // WHEN + new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { + vpc, + service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), + subnets: { + subnetFilters: [new ContainsIpAddressesSubnetSelector(['10.0.96.0', '10.0.160.0'])], + }, + }); + + // THEN + expect(stack).to(haveResource('AWS::EC2::VPCEndpoint', { + ServiceName: 'com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', + SubnetIds: [ + { + Ref: 'VPCPrivateSubnet1Subnet8BCA10E0', + }, + { + Ref: 'VPCPrivateSubnet3Subnet3EDCD457', + }, + ], + })); + test.done(); + }, }, }); From be6dabd4f5aacd2901999355b93a76d60116b9b2 Mon Sep 17 00:00:00 2001 From: James Fleming Date: Wed, 2 Sep 2020 01:51:24 +0000 Subject: [PATCH 07/14] README update --- packages/@aws-cdk/aws-ec2/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index bf26132b35a07..689430c46fdf8 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -163,6 +163,8 @@ Which subnets are selected is evaluated as follows: in the given availability zones will be returned. * `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 + implement the ISubnetSelector interface. ### Using NAT instances From 0cc51f7b0ec0bb55e308d7c5222a265a8340cf8e Mon Sep 17 00:00:00 2001 From: James Fleming Date: Tue, 8 Sep 2020 13:21:52 +0000 Subject: [PATCH 08/14] Remove double quotes being ignored by linter --- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 662c196e17c16..71c1c0fd307c0 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -1933,7 +1933,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public get availabilityZone(): string { if (!this._availabilityZone) { // eslint-disable-next-line max-len - throw new Error("You cannot reference a Subnet's availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()"); + throw new Error('You cannot reference a Subnet's availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()'); } return this._availabilityZone; } @@ -1941,7 +1941,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public get ipv4CidrBlock(): string { if (!this._ipv4CidrBlock) { // tslint:disable-next-line: max-line-length - throw new Error("You cannot reference an imported Subnet's IPv4 CIDR if it was not supplied. Add the ipv4CidrBlock when importing using Subnet.fromSubnetAttributes()"); + throw new Error('You cannot reference an imported Subnet's IPv4 CIDR if it was not supplied. Add the ipv4CidrBlock when importing using Subnet.fromSubnetAttributes()'); } return this._ipv4CidrBlock; } From 32fdd47679e3bebfd964ac01dee1e512ef74517d Mon Sep 17 00:00:00 2001 From: James Fleming Date: Tue, 8 Sep 2020 13:47:22 +0000 Subject: [PATCH 09/14] Forgot to escape --- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 71c1c0fd307c0..11dca54b89cca 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -1933,7 +1933,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public get availabilityZone(): string { if (!this._availabilityZone) { // eslint-disable-next-line max-len - throw new Error('You cannot reference a Subnet's availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()'); + throw new Error('You cannot reference a Subnet\'s availability zone if it was not supplied. Add the availabilityZone when importing using Subnet.fromSubnetAttributes()'); } return this._availabilityZone; } @@ -1941,7 +1941,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public get ipv4CidrBlock(): string { if (!this._ipv4CidrBlock) { // tslint:disable-next-line: max-line-length - throw new Error('You cannot reference an imported Subnet's IPv4 CIDR if it was not supplied. Add the ipv4CidrBlock when importing using Subnet.fromSubnetAttributes()'); + throw new Error('You cannot reference an imported Subnet\'s IPv4 CIDR if it was not supplied. Add the ipv4CidrBlock when importing using Subnet.fromSubnetAttributes()'); } return this._ipv4CidrBlock; } From 5609f93249f53f6c116ca6491d0f80c1f28e0f3d Mon Sep 17 00:00:00 2001 From: James Fleming Date: Tue, 8 Sep 2020 14:25:22 +0000 Subject: [PATCH 10/14] Change name to SubnetFilter --- packages/@aws-cdk/aws-ec2/lib/subnet.ts | 8 ++++---- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 10 +++++----- packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/subnet.ts b/packages/@aws-cdk/aws-ec2/lib/subnet.ts index f51c7e7d13ae0..8a21ef4611bd1 100644 --- a/packages/@aws-cdk/aws-ec2/lib/subnet.ts +++ b/packages/@aws-cdk/aws-ec2/lib/subnet.ts @@ -6,7 +6,7 @@ import { ISubnet } from './vpc'; * with SubnetSelection, to determine where to place AWS resources such as VPC * endpoints, EC2 instances, etc. */ -export interface ISubnetSelector { +export interface ISubnetFilter { /** * Executes the subnet filtering logic, returning a filtered set of subnets. @@ -17,7 +17,7 @@ export interface ISubnetSelector { /** * Chooses subnets which are in one of the given availability zones. */ -export class AvailabilityZoneSubnetSelector implements ISubnetSelector { +export class AvailabilityZoneSubnetFilter implements ISubnetFilter { private readonly availabilityZones: string[]; @@ -36,7 +36,7 @@ export class AvailabilityZoneSubnetSelector implements ISubnetSelector { /** * Chooses subnets such that there is at most one per availability zone. */ -export class OnePerAZSubnetSelector implements ISubnetSelector { +export class OnePerAZSubnetFilter implements ISubnetFilter { constructor() {} @@ -60,7 +60,7 @@ export class OnePerAZSubnetSelector implements ISubnetSelector { /** * Chooses subnets which contain any of the specified IP addresses. */ -export class ContainsIpAddressesSubnetSelector implements ISubnetSelector { +export class ContainsIpAddressesSubnetFilter implements ISubnetFilter { private readonly ipAddresses: string[]; diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 11dca54b89cca..63ccd446f575d 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -11,7 +11,7 @@ import { import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; import { NetworkBuilder } from './network-util'; -import { AvailabilityZoneSubnetSelector, OnePerAZSubnetSelector, ISubnetSelector } from './subnet'; +import { AvailabilityZoneSubnetFilter, OnePerAZSubnetFilter, ISubnetFilter } from './subnet'; import { allRouteTableIds, defaultSubnetName, flatten, ImportSubnetGroup, subnetGroupNameFromConstructId, subnetId } from './util'; import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, GatewayVpcEndpointOptions, InterfaceVpcEndpoint, InterfaceVpcEndpointOptions } from './vpc-endpoint'; import { FlowLog, FlowLogOptions, FlowLogResourceType } from './vpc-flow-logs'; @@ -247,7 +247,7 @@ export interface SubnetSelection { * * @default - none */ - readonly subnetFilters?: ISubnetSelector[]; + readonly subnetFilters?: ISubnetFilter[]; /** * Explicitly select individual subnets @@ -479,7 +479,7 @@ abstract class VpcBase extends Resource implements IVpc { return subnets; } - private applySubnetFilters(subnets: ISubnet[], filters: ISubnetSelector[]): ISubnet[] { + private applySubnetFilters(subnets: ISubnet[], filters: ISubnetFilter[]): ISubnet[] { let filtered = subnets; // Apply each filter in sequence for (const filter of filters) { @@ -554,10 +554,10 @@ abstract class VpcBase extends Resource implements IVpc { // Backwards compatibility with existing `availabilityZones` and `onePerAz` functionality if (placement.availabilityZones !== undefined) { // Filter by AZs, if specified - subnetFilters.push(new AvailabilityZoneSubnetSelector(placement.availabilityZones)); + subnetFilters.push(new AvailabilityZoneSubnetFilter(placement.availabilityZones)); } if (!!placement.onePerAz) { // Ensure one per AZ if specified - subnetFilters.push(new OnePerAZSubnetSelector()); + subnetFilters.push(new OnePerAZSubnetFilter()); } // Overwrite the provided placement filters diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 1df7904907f91..2fc79b20c074c 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -2,7 +2,7 @@ import { countResources, expect, haveResource, haveResourceLike, isSuperObject, import { CfnOutput, Lazy, Stack, Tags } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { - AclCidr, AclTraffic, BastionHostLinux, CfnSubnet, CfnVPC, ContainsIpAddressesSubnetSelector, DefaultInstanceTenancy, GenericLinuxImage, + AclCidr, AclTraffic, BastionHostLinux, CfnSubnet, CfnVPC, ContainsIpAddressesSubnetFilter, DefaultInstanceTenancy, GenericLinuxImage, InstanceType, InterfaceVpcEndpoint, InterfaceVpcEndpointService, NatProvider, NetworkAcl, NetworkAclEntry, Peer, Port, PrivateSubnet, PublicSubnet, RouterType, Subnet, SubnetType, TrafficDirection, Vpc, } from '../lib'; @@ -1398,7 +1398,7 @@ nodeunitShim({ new BastionHostLinux(stack, 'Bastion', { vpc, subnetSelection: { - subnetFilters: [new ContainsIpAddressesSubnetSelector(['10.0.160.0'])], + subnetFilters: [new ContainsIpAddressesSubnetFilter(['10.0.160.0'])], }, }); @@ -1431,7 +1431,7 @@ nodeunitShim({ vpc, service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), subnets: { - subnetFilters: [new ContainsIpAddressesSubnetSelector(['10.0.96.0', '10.0.160.0'])], + subnetFilters: [new ContainsIpAddressesSubnetFilter(['10.0.96.0', '10.0.160.0'])], }, }); From 59af473ac42c4343b4137318d1e124f3558e9b5a Mon Sep 17 00:00:00 2001 From: James Fleming Date: Tue, 8 Sep 2020 14:49:46 +0000 Subject: [PATCH 11/14] merge conflict --- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 63ccd446f575d..929a344d3d155 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -1,7 +1,7 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { - Annotations, ConcreteDependable, Construct, ContextProvider, DependableTrait, - IConstruct, IDependable, IResource, Lazy, Resource, Stack, Token, Tags, + Annotations, ConcreteDependable, Construct, ContextProvider, DependableTrait, IConstruct, + IDependable, IResource, Lazy, Resource, Stack, Token, Tags, } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { From 724b2a587009cc9652a60f412b61f6ca88f0504a Mon Sep 17 00:00:00 2001 From: James Fleming Date: Tue, 8 Sep 2020 17:39:15 +0000 Subject: [PATCH 12/14] Change from interface to minimal abstract class --- packages/@aws-cdk/aws-ec2/lib/subnet.ts | 39 ++++++++++++++++++---- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 10 +++--- packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 6 ++-- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/subnet.ts b/packages/@aws-cdk/aws-ec2/lib/subnet.ts index 8a21ef4611bd1..204c81957c929 100644 --- a/packages/@aws-cdk/aws-ec2/lib/subnet.ts +++ b/packages/@aws-cdk/aws-ec2/lib/subnet.ts @@ -6,22 +6,46 @@ import { ISubnet } from './vpc'; * with SubnetSelection, to determine where to place AWS resources such as VPC * endpoints, EC2 instances, etc. */ -export interface ISubnetFilter { +export abstract class SubnetFilter { + + /** + * Chooses subnets which are in one of the given availability zones. + */ + public static availabilityZones(availabilityZones: string[]): SubnetFilter { + return new AvailabilityZoneSubnetFilter(availabilityZones); + } + + /** + * Chooses subnets such that there is at most one per availability zone. + */ + public static onePerAz(): SubnetFilter { + return new OnePerAZSubnetFilter(); + } + + /** + * Chooses subnets which contain any of the specified IP addresses. + */ + public static containsIpAddresses(ipv4addrs: string[]): SubnetFilter { + return new ContainsIpAddressesSubnetFilter(ipv4addrs); + } /** * Executes the subnet filtering logic, returning a filtered set of subnets. */ - selectSubnets(subnets: ISubnet[]): ISubnet[]; + public selectSubnets(_subnets: ISubnet[]): ISubnet[] { + throw new Error('Cannot select subnets with an abstract SubnetFilter. `selectSubnets` needs to be implmemented.'); + } } /** * Chooses subnets which are in one of the given availability zones. */ -export class AvailabilityZoneSubnetFilter implements ISubnetFilter { +class AvailabilityZoneSubnetFilter extends SubnetFilter { private readonly availabilityZones: string[]; constructor(availabilityZones: string[]) { + super(); this.availabilityZones = availabilityZones; } @@ -36,9 +60,11 @@ export class AvailabilityZoneSubnetFilter implements ISubnetFilter { /** * Chooses subnets such that there is at most one per availability zone. */ -export class OnePerAZSubnetFilter implements ISubnetFilter { +class OnePerAZSubnetFilter extends SubnetFilter { - constructor() {} + constructor() { + super(); + } /** * Executes the subnet filtering logic. @@ -60,11 +86,12 @@ export class OnePerAZSubnetFilter implements ISubnetFilter { /** * Chooses subnets which contain any of the specified IP addresses. */ -export class ContainsIpAddressesSubnetFilter implements ISubnetFilter { +class ContainsIpAddressesSubnetFilter extends SubnetFilter { private readonly ipAddresses: string[]; constructor(ipAddresses: string[]) { + super(); this.ipAddresses = ipAddresses; } diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index abdf9607a2c65..9ac8cf43a3f72 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -11,7 +11,7 @@ import { import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; import { NetworkBuilder } from './network-util'; -import { AvailabilityZoneSubnetFilter, OnePerAZSubnetFilter, ISubnetFilter } from './subnet'; +import { SubnetFilter } from './subnet'; import { allRouteTableIds, defaultSubnetName, flatten, ImportSubnetGroup, subnetGroupNameFromConstructId, subnetId } from './util'; import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, GatewayVpcEndpointOptions, InterfaceVpcEndpoint, InterfaceVpcEndpointOptions } from './vpc-endpoint'; import { FlowLog, FlowLogOptions, FlowLogResourceType } from './vpc-flow-logs'; @@ -247,7 +247,7 @@ export interface SubnetSelection { * * @default - none */ - readonly subnetFilters?: ISubnetFilter[]; + readonly subnetFilters?: SubnetFilter[]; /** * Explicitly select individual subnets @@ -479,7 +479,7 @@ abstract class VpcBase extends Resource implements IVpc { return subnets; } - private applySubnetFilters(subnets: ISubnet[], filters: ISubnetFilter[]): ISubnet[] { + private applySubnetFilters(subnets: ISubnet[], filters: SubnetFilter[]): ISubnet[] { let filtered = subnets; // Apply each filter in sequence for (const filter of filters) { @@ -554,10 +554,10 @@ abstract class VpcBase extends Resource implements IVpc { // Backwards compatibility with existing `availabilityZones` and `onePerAz` functionality if (placement.availabilityZones !== undefined) { // Filter by AZs, if specified - subnetFilters.push(new AvailabilityZoneSubnetFilter(placement.availabilityZones)); + subnetFilters.push(SubnetFilter.availabilityZones(placement.availabilityZones)); } if (!!placement.onePerAz) { // Ensure one per AZ if specified - subnetFilters.push(new OnePerAZSubnetFilter()); + subnetFilters.push(SubnetFilter.onePerAz()); } // Overwrite the provided placement filters diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 2fc79b20c074c..9163a210738f8 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -2,7 +2,7 @@ import { countResources, expect, haveResource, haveResourceLike, isSuperObject, import { CfnOutput, Lazy, Stack, Tags } from '@aws-cdk/core'; import { nodeunitShim, Test } from 'nodeunit-shim'; import { - AclCidr, AclTraffic, BastionHostLinux, CfnSubnet, CfnVPC, ContainsIpAddressesSubnetFilter, DefaultInstanceTenancy, GenericLinuxImage, + AclCidr, AclTraffic, BastionHostLinux, CfnSubnet, CfnVPC, SubnetFilter, DefaultInstanceTenancy, GenericLinuxImage, InstanceType, InterfaceVpcEndpoint, InterfaceVpcEndpointService, NatProvider, NetworkAcl, NetworkAclEntry, Peer, Port, PrivateSubnet, PublicSubnet, RouterType, Subnet, SubnetType, TrafficDirection, Vpc, } from '../lib'; @@ -1398,7 +1398,7 @@ nodeunitShim({ new BastionHostLinux(stack, 'Bastion', { vpc, subnetSelection: { - subnetFilters: [new ContainsIpAddressesSubnetFilter(['10.0.160.0'])], + subnetFilters: [SubnetFilter.containsIpAddresses(['10.0.160.0'])], }, }); @@ -1431,7 +1431,7 @@ nodeunitShim({ vpc, service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), subnets: { - subnetFilters: [new ContainsIpAddressesSubnetFilter(['10.0.96.0', '10.0.160.0'])], + subnetFilters: [SubnetFilter.containsIpAddresses(['10.0.96.0', '10.0.160.0'])], }, }); From d691e0c659970d343337489dc0c848088ba14b3f Mon Sep 17 00:00:00 2001 From: flemjame-at-amazon <57235867+flemjame-at-amazon@users.noreply.github.com> Date: Wed, 9 Sep 2020 10:20:44 -0400 Subject: [PATCH 13/14] Update README.md --- packages/@aws-cdk/aws-ec2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 689430c46fdf8..27dcabd8b69cd 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -164,7 +164,7 @@ 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 - implement the ISubnetSelector interface. + extend the SubnetFilter class. ### Using NAT instances From 84c6ae1435ccb273a0f4697023c6a3bd51806d3c Mon Sep 17 00:00:00 2001 From: James Fleming Date: Fri, 11 Sep 2020 19:12:23 +0000 Subject: [PATCH 14/14] Remove azs and one per az from reifySelectionDefaults --- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 9ac8cf43a3f72..9b7943a7d36e6 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -560,10 +560,11 @@ abstract class VpcBase extends Resource implements IVpc { subnetFilters.push(SubnetFilter.onePerAz()); } - // Overwrite the provided placement filters - placement = { ...placement, subnetFilters: subnetFilters }; + // Overwrite the provided placement filters and remove the availabilityZones and onePerAz properties + placement = { ...placement, subnetFilters: subnetFilters, availabilityZones: undefined, onePerAz: undefined }; + const { availabilityZones, onePerAz, ...rest } = placement; - return placement; + return rest; } }