From fd7ec93fb2156c578224b1e11637d847a8c39209 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 10 Oct 2022 09:58:35 +0100 Subject: [PATCH 01/20] WIP --- packages/@aws-cdk/aws-ec2/README.md | 36 ++ packages/@aws-cdk/aws-ec2/lib/cidr-splits.ts | 77 ++++ packages/@aws-cdk/aws-ec2/lib/index.ts | 1 + packages/@aws-cdk/aws-ec2/lib/ipam.ts | 315 ++++++++++++++ packages/@aws-cdk/aws-ec2/lib/vpc.ts | 82 ++-- .../@aws-cdk/aws-ec2/test/cidr-splits.test.ts | 39 ++ .../@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts | 84 ++++ packages/@aws-cdk/aws-ec2/test/ipam.test.ts | 410 ++++++++++++++++++ packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 9 +- 9 files changed, 1023 insertions(+), 30 deletions(-) create mode 100644 packages/@aws-cdk/aws-ec2/lib/cidr-splits.ts create mode 100644 packages/@aws-cdk/aws-ec2/lib/ipam.ts create mode 100644 packages/@aws-cdk/aws-ec2/test/cidr-splits.test.ts create mode 100644 packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts create mode 100644 packages/@aws-cdk/aws-ec2/test/ipam.test.ts diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index c7b8613c4f6eb..b662f5b302f05 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -217,6 +217,42 @@ new ec2.Vpc(this, 'TheVPC', { provider.connections.allowFrom(ec2.Peer.ipv4('1.2.3.4/8'), ec2.Port.tcp(80)); ``` +### Ip Address Management - IPAM + +To facilitate options for flexibility in the allocation and use of IP space within Vpc and Subnet including strategy and implementation for the allocation, Vpc utilizes an IpamProvider. + +By default, the Vpc construct will create and use a StaticIpam for you if you do not pass an `ipamProvider` to Vpc. StaticIpam is an implementation of the Original CDK Vpc and Subnet IP address allocation strategy and implementation. + +You must supply at most one of ipamProvider or cidr to Vpc. + +StaticIpam will first try to allocated space from the Vpc Cidr any Subnets that explicitly have a `cidrMask` as part of a SubnetConfiguration, this includes reserved subnets, after this any remaining space is divided between the rest of the required subnets. + +When using StaticIpam concrete Cidr values are generated in the synthesized CloudFormation template. + +```ts +new ec2.Vpc(stack, 'TheVPC', { + ipamProvider: new ec2.StaticIpam('10.0.1.0/20') +}); +``` + +AwsIpam uses Amazon VPC IP Address Manager (IPAM) to allocated the Cidr for the Vpc. For information on Amazon VPC IP Address Manager please see the [official documentation](https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html). + +AWS Ipam requires a `ipv4IpamPoolId` be set to the Amazon VPC IP Address Manager Pool Id used for the Vpc Cidr allocation, additionally an `ipv4NetmaskLength` must be set, which defines the size of cidr that will be requested from the Pool at deploy time by the CloudFormation engine. + +Subnets are allocated locally of a size defined by `defaultSubnetIpv4NetmaskLength` in the provider or by using any explicit `cidrMask` from a supplied SubnetConfiguration. The provider AwsIpam dose not attempt to allocated any remaining space in the Vpc's Cidr space. + +```ts +new ec2.Vpc(stack, 'TheVPC', { + ipamProvider: new ec2.AwsIpam({ + ipv4IpamPoolId: pool.ref, + ipv4NetmaskLength: 18, + defaultSubnetIpv4NetmaskLength: 24 + }) +}); +``` + +When using AwsIpam the final Cidr allocation for Vpc and Subnets are unknown at synth time. Because of this Subnet Cidr values are synthesized as CloudFormation Intrinsic functions representing their offset within the Vpc Cidr space and not concrete values. + ### Advanced Subnet Configuration If the default VPC configuration (public and private subnets spanning the diff --git a/packages/@aws-cdk/aws-ec2/lib/cidr-splits.ts b/packages/@aws-cdk/aws-ec2/lib/cidr-splits.ts new file mode 100644 index 0000000000000..04d976007fc5c --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/lib/cidr-splits.ts @@ -0,0 +1,77 @@ +/** + * Return the splits necessary to allocate the given sequence of cidrs in the given order + * + * The entire block is of size 'rootNetmask', and subsequent blocks will be allocated + * from it sized according to the sizes in the 'netmasks' array. + * + * The return value is a list of `CidrSplit` objects, which represent + * invocations of a pair of `Fn.select(Fn.cidr(...))` operations. + * + * Strategy: walk through the IP block space, clipping to the next possible + * start of a block of the given size, then allocate it. Here is an unrealistic + * example (with a weird ordering of the netmasks to show how clipping and hence + * space wasting plays out in practice): + * + * root space /16 + * ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ + * │ │ + * A /21 B /19 + * ┌───┬───┬───┬───┬───────────────┬───────────────┬───┬───────────┬───────────────┬──────────────┐ + * │ A │ A │ A │###│ B │ B │ A │###########│ B │ .... │ + * └───┴───┴───┴───┴───────────────┴───────────────┴───┴───────────┴───────────────┴──────────────┘ + * ^^^______ wasted space _________________^^^^^^ + */ +export function calculateCidrSplits(rootNetmask: number, netmasks: number[]): CidrSplit[] { + const ret = new Array(); + + let offset = 0; + for (const netmask of netmasks) { + const size = Math.pow(2, 32 - netmask); + + // Clip offset to the next block of the given size + offset = nextMultiple(offset, size); + + const count = Math.pow(2, netmask - rootNetmask); + ret.push({ + count, + netmask, + index: offset / size, + }); + + // Consume + offset += size; + } + + if (offset > Math.pow(2, 32 - rootNetmask)) { + throw new Error(`IP space of size /${rootNetmask} not big enough to allocate subnets of sizes ${netmasks.map(x => `/${x}`)}`); + } + + return ret; +} + +function nextMultiple(current: number, multiple: number) { + return Math.ceil(current / multiple) * multiple; +} + +/** + * A representation of a pair of `Fn.select(Fn.cidr())` invocations + */ +export interface CidrSplit { + /** + * The netmask of this block size + * + * This is the inverse number of what you need to pass to Fn.cidr (pass `32 - + * netmask` to Fn.cidr)`. + */ + readonly netmask: number; + + /** + * How many parts the mask needs to be split into + */ + readonly count: number; + + /** + * What subnet index to select from the split + */ + readonly index: number; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/lib/index.ts b/packages/@aws-cdk/aws-ec2/lib/index.ts index 4b0741044e4dd..4e65cd23c8054 100644 --- a/packages/@aws-cdk/aws-ec2/lib/index.ts +++ b/packages/@aws-cdk/aws-ec2/lib/index.ts @@ -27,6 +27,7 @@ export * from './client-vpn-endpoint-types'; export * from './client-vpn-endpoint'; export * from './client-vpn-authorization-rule'; export * from './client-vpn-route'; +export * from './ipam'; // AWS::EC2 CloudFormation Resources: export * from './ec2.generated'; diff --git a/packages/@aws-cdk/aws-ec2/lib/ipam.ts b/packages/@aws-cdk/aws-ec2/lib/ipam.ts new file mode 100644 index 0000000000000..1e07d61728ded --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/lib/ipam.ts @@ -0,0 +1,315 @@ +import { Fn } from '@aws-cdk/core'; +import { calculateCidrSplits } from './cidr-splits'; +import { NetworkBuilder } from './network-util'; +import { SubnetConfiguration } from './vpc'; + +/** + * An abstract Provider of Ipam + */ +export abstract class IpamProvider { + /** + * Used to provide local Ip Address Management services for your VPC + * + * VPC Cidr is supplied at creation and subnets are calculated locally + * + */ + public static staticIpam(cidrBlock: string): IpamProvider { + return new StaticIpam(cidrBlock); + } + + /** + * Used to provide centralized Ip Address Management services for your VPC + * + * Uses VPC Cidr allocations from AWS IPAM + * + * @see https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html + */ + public static awsIpam(props: AwsIpamProps): IpamProvider { + return new AwsIpam(props); + } + + /** + * Called by the VPC to retrieve VPC options from the Ipam + * + * Don't call this directly, the VPC will call it automatically. + */ + public abstract allocateVpcCidr(): VpcIpamOptions; + + /** + * Called by the VPC to retrieve Subnet options from the Ipam + * + * Don't call this directly, the VPC will call it automatically. + */ + public abstract allocateSubnetsCidr(input: AllocateCidrRequest): SubnetIpamOptions; +} + +/** + * Provider of Ipam Implementations + */ +export interface IIpamProvider { + /** + * Allocates Cidr for Vpc + */ + allocateVpcCidr(): VpcIpamOptions; + + /** + * Allocates Cidr for Subnets + */ + allocateSubnetsCidr(input: AllocateCidrRequest): SubnetIpamOptions; +} + +/** + * Cidr Allocated Vpc + */ +export interface VpcIpamOptions { + + /** + * Cidr Block for Vpc + * + * @default - Only required when Ipam has concrete allocation available for static Vpc + */ + readonly cidrBlock?: string; + + /** + * Cidr Mask for Vpc + * + * @default - Only required when using AWS Ipam + */ + readonly ipv4NetmaskLength?: number; + + /** + * ipv4 IPAM Pool Id + * + * @default - Only required when using AWS Ipam + */ + readonly ipv4IpamPoolId?: string; +} + +/** + * Subnet requested for allocation + */ +export interface RequestedSubnet { + + /** + * The availability zone for the subnet + */ + readonly availabilityZone: string; + + /** + * Specify configuration parameters for a single subnet group in a VPC + */ + readonly configuration: SubnetConfiguration; + + /** + * Id for the Subnet construct + */ + readonly subnetConstructId: string; +} + +/** + * An instance of a Subnet requested for allocation + */ +interface IRequestedSubnetInstance { + /** + * Index location of Subnet requested for allocation + */ + readonly index: number, + + /** + * Subnet requested for allocation + */ + readonly requestedSubnet: RequestedSubnet +} + +/** + * Request for subnets Cidr to be allocated for a Vpc + */ +export interface AllocateCidrRequest { + + /** + * The IPv4 CIDR block for this Vpc + */ + readonly vpcCidr: string; + + /** + * The Subnets to be allocated + */ + readonly requestedSubnets: RequestedSubnet[]; +} + +/** + * Cidr Allocated Subnets + */ +export interface SubnetIpamOptions { + /** + * Cidr Allocations for Subnets + */ + readonly allocatedSubnets: AllocatedSubnet[]; +} + +/** + * Cidr Allocated Subnet + */ +export interface AllocatedSubnet { + /** + * Cidr Allocations for a Subnet + */ + readonly cidr: string; +} + +/** + * Configuration for AwsIpam + */ +export interface AwsIpamProps { + + /** + * Netmask length for Vpc + */ + readonly ipv4NetmaskLength: number; + + /** + * Ipam Pool Id for ipv4 allocation + */ + readonly ipv4IpamPoolId: string; // todo: should be a type + + /** + * Default length for Subnet ipv4 Network mask + * + * Specify this option only if you do not specify all Subnets using SubnetConfiguration with a cidrMask + * + * @default - Default ipv4 Subnet Mask for subnets in Vpc + * + */ + readonly defaultSubnetIpv4NetmaskLength?: number; +} + +/** + * Implements integration with Amazon VPC IP Address Manager (IPAM). + * + * See the package-level documentation of this package for an overview + * of the various dimensions in which you can configure your VPC. + * + * For example: + * + * ```ts + * new ec2.Vpc(stack, 'TheVPC', { + * ipamProvider: new ec2.AwsIpam({ + * ipv4IpamPoolId: pool.ref, + * ipv4NetmaskLength: 18, + * defaultSubnetIpv4NetmaskLength: 24 + * }) + * }); + * ``` + * + */ +export class AwsIpam implements IIpamProvider { + constructor(private readonly props: AwsIpamProps) {} + + /** + * Allocates Vpc Cidr. called when creating a Vpc using AwsIpam. + */ + allocateVpcCidr(): VpcIpamOptions { + return { + ipv4NetmaskLength: this.props.ipv4NetmaskLength, + ipv4IpamPoolId: this.props.ipv4IpamPoolId, + }; + } + + /** + * Allocates Subnets Cidrs. Called by VPC when creating subnets. + */ + allocateSubnetsCidr(input: AllocateCidrRequest): SubnetIpamOptions { + + const cidrSplit = calculateCidrSplits(this.props.ipv4NetmaskLength, input.requestedSubnets.map((mask => { + + if ((mask.configuration.cidrMask === undefined) && (this.props.defaultSubnetIpv4NetmaskLength=== undefined) ) { + throw new Error('If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in the provider'); + } + + const cidrMask = mask.configuration.cidrMask ?? this.props.defaultSubnetIpv4NetmaskLength; + + if (cidrMask === undefined) { + throw new Error('Should not have happened, but satisfies the type checker'); + } + + return cidrMask; + }))); + + const allocatedSubnets: AllocatedSubnet[] = cidrSplit.map(subnet => { + return { + cidr: Fn.select(subnet.index, Fn.cidr(input.vpcCidr, subnet.count, `${32-subnet.netmask}`)), + }; + }); + + return { + allocatedSubnets: allocatedSubnets, + }; + + } +} + +/** + * Implements static Ip assignment locally. + * + * See the package-level documentation of this package for an overview + * of the various dimensions in which you can configure your VPC. + * + * For example: + * + * ```ts + * new ec2.Vpc(stack, 'TheVPC', { + * ipamProvider: new ec2.StaticIpam('10.0.1.0/20') + * }); + * ``` + * + */ +export class StaticIpam implements IIpamProvider { + private readonly networkBuilder: NetworkBuilder; + + constructor(private readonly cidrBlock: string) { + this.networkBuilder = new NetworkBuilder(this.cidrBlock); + } + + /** + * Allocates Vpc Cidr. called when creating a Vpc using StaticIpam. + */ + allocateVpcCidr(): VpcIpamOptions { + return { + cidrBlock: this.networkBuilder.networkCidr.cidr, + }; + } + + /** + * Allocates Subnets Cidrs. Called by VPC when creating subnets. + */ + allocateSubnetsCidr(input: AllocateCidrRequest): SubnetIpamOptions { + + const allocatedSubnets: AllocatedSubnet[] = []; + const subnetsWithoutDefinedCidr: IRequestedSubnetInstance[] = []; + //default: Available IP space is evenly divided across subnets if no cidr is given. + + input.requestedSubnets.forEach((requestedSubnet, index) => { + if (requestedSubnet.configuration.cidrMask === undefined) { + subnetsWithoutDefinedCidr.push({ + index, + requestedSubnet, + }); + } else { + allocatedSubnets.push({ + cidr: this.networkBuilder.addSubnet(requestedSubnet.configuration.cidrMask), + }); + } + }); + + const cidrMaskForRemaining = this.networkBuilder.maskForRemainingSubnets(subnetsWithoutDefinedCidr.length); + subnetsWithoutDefinedCidr.forEach((subnet)=> { + allocatedSubnets.splice(subnet.index, 0, { + cidr: this.networkBuilder.addSubnet(cidrMaskForRemaining), + }); + }); + + return { + allocatedSubnets: allocatedSubnets, + }; + } +} \ 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 7d60c335c0637..b7e4dc1972329 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -10,9 +10,9 @@ import { CfnEIP, CfnInternetGateway, CfnNatGateway, CfnRoute, CfnRouteTable, CfnSubnet, CfnSubnetRouteTableAssociation, CfnVPC, CfnVPCGatewayAttachment, CfnVPNGatewayRoutePropagation, } from './ec2.generated'; +import { AllocatedSubnet, IIpamProvider, RequestedSubnet, StaticIpam } from './ipam'; import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; -import { NetworkBuilder } from './network-util'; import { SubnetFilter } from './subnet'; import { allRouteTableIds, defaultSubnetName, flatten, ImportSubnetGroup, subnetGroupNameFromConstructId, subnetId } from './util'; import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, GatewayVpcEndpointOptions, InterfaceVpcEndpoint, InterfaceVpcEndpointOptions } from './vpc-endpoint'; @@ -811,6 +811,15 @@ const NAME_TAG: string = 'Name'; */ export interface VpcProps { + /** + * The Ipam Provider to use to allocate IP Space to your VPC. + * + * Options include static allocation or from a pool. + * + * @default ipam.StaticIpam + */ + readonly ipamProvider?: IIpamProvider; + /** * The CIDR range to use for the VPC, e.g. '10.0.0.0/16'. * @@ -818,6 +827,8 @@ export interface VpcProps { * split across all subnets per Availability Zone. * * @default Vpc.DEFAULT_CIDR_RANGE + * + * @deprecated Use ipamProvider instead */ readonly cidr?: string; @@ -1303,9 +1314,9 @@ export class Vpc extends VpcBase { private readonly resource: CfnVPC; /** - * The NetworkBuilder + * The IPAM provider */ - private networkBuilder: NetworkBuilder; + private readonly ipamProvider: IIpamProvider; /** * Subnet configurations for this VPC @@ -1339,16 +1350,24 @@ export class Vpc extends VpcBase { throw new Error('\'cidr\' property must be a concrete CIDR string, got a Token (we need to parse it for automatic subdivision)'); } - this.networkBuilder = new NetworkBuilder(cidrBlock); + if (props.ipamProvider && props.cidr) { + throw new Error('supply at most one of ipamProvider or cidr'); + } + + this.ipamProvider = props.ipamProvider ?? new StaticIpam(cidrBlock); this.dnsHostnamesEnabled = props.enableDnsHostnames == null ? true : props.enableDnsHostnames; this.dnsSupportEnabled = props.enableDnsSupport == null ? true : props.enableDnsSupport; const instanceTenancy = props.defaultInstanceTenancy || 'default'; this.internetConnectivityEstablished = this._internetConnectivityEstablished; + const vpcIpamOptions = this.ipamProvider.allocateVpcCidr(); + // Define a VPC using the provided CIDR range this.resource = new CfnVPC(this, 'Resource', { - cidrBlock, + cidrBlock: vpcIpamOptions.cidrBlock, + ipv4IpamPoolId: vpcIpamOptions.ipv4IpamPoolId, + ipv4NetmaskLength: vpcIpamOptions.ipv4NetmaskLength, enableDnsHostnames: this.dnsHostnamesEnabled, enableDnsSupport: this.dnsSupportEnabled, instanceTenancy, @@ -1508,28 +1527,38 @@ export class Vpc extends VpcBase { * array or creates the `DEFAULT_SUBNETS` configuration */ private createSubnets() { - const remainingSpaceSubnets: SubnetConfiguration[] = []; - for (const subnet of this.subnetConfiguration) { - if (subnet.cidrMask === undefined) { - remainingSpaceSubnets.push(subnet); - continue; - } - this.createSubnetResources(subnet, subnet.cidrMask); - } + const requestedSubnets: RequestedSubnet[] = []; - const totalRemaining = remainingSpaceSubnets.length * this.availabilityZones.length; - const cidrMaskForRemaining = this.networkBuilder.maskForRemainingSubnets(totalRemaining); - for (const subnet of remainingSpaceSubnets) { - this.createSubnetResources(subnet, cidrMaskForRemaining); + this.subnetConfiguration.forEach((configuration)=> ( + this.availabilityZones.forEach((az, index) => { + requestedSubnets.push({ + availabilityZone: az, + subnetConstructId: subnetId(configuration.name, index), + configuration, + }); + }, + ))); + + const { allocatedSubnets } = this.ipamProvider.allocateSubnetsCidr({ + vpcCidr: this.vpcCidrBlock, + requestedSubnets, + }); + + if (allocatedSubnets.length != requestedSubnets.length) { + throw new Error('Incomplete Subnet Allocation; response array dose not equal input array'); } + + this.createSubnetResources(requestedSubnets, allocatedSubnets); } - private createSubnetResources(subnetConfig: SubnetConfiguration, cidrMask: number) { - this.availabilityZones.forEach((zone, index) => { + private createSubnetResources(requestedSubnets: RequestedSubnet[], allocatedSubnets: AllocatedSubnet[]) { + allocatedSubnets.forEach((allocated, i) => { + + const { configuration: subnetConfig, subnetConstructId, availabilityZone } = requestedSubnets[i]; + if (subnetConfig.reserved === true) { - // For reserved subnets, just allocate ip space but do not create any resources - this.networkBuilder.addSubnet(cidrMask); + // For reserved subnets, do not create any resources return; } @@ -1544,31 +1573,30 @@ export class Vpc extends VpcBase { : true; } - const name = subnetId(subnetConfig.name, index); const subnetProps: SubnetProps = { - availabilityZone: zone, + availabilityZone, vpcId: this.vpcId, - cidrBlock: this.networkBuilder.addSubnet(cidrMask), + cidrBlock: allocated.cidr, mapPublicIpOnLaunch: mapPublicIpOnLaunch, }; let subnet: Subnet; switch (subnetConfig.subnetType) { case SubnetType.PUBLIC: - const publicSubnet = new PublicSubnet(this, name, subnetProps); + const publicSubnet = new PublicSubnet(this, subnetConstructId, subnetProps); this.publicSubnets.push(publicSubnet); subnet = publicSubnet; break; case SubnetType.PRIVATE_WITH_EGRESS: case SubnetType.PRIVATE_WITH_NAT: case SubnetType.PRIVATE: - const privateSubnet = new PrivateSubnet(this, name, subnetProps); + const privateSubnet = new PrivateSubnet(this, subnetConstructId, subnetProps); this.privateSubnets.push(privateSubnet); subnet = privateSubnet; break; case SubnetType.PRIVATE_ISOLATED: case SubnetType.ISOLATED: - const isolatedSubnet = new PrivateSubnet(this, name, subnetProps); + const isolatedSubnet = new PrivateSubnet(this, subnetConstructId, subnetProps); this.isolatedSubnets.push(isolatedSubnet); subnet = isolatedSubnet; break; diff --git a/packages/@aws-cdk/aws-ec2/test/cidr-splits.test.ts b/packages/@aws-cdk/aws-ec2/test/cidr-splits.test.ts new file mode 100644 index 0000000000000..af7d43dde687e --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/cidr-splits.test.ts @@ -0,0 +1,39 @@ +import { calculateCidrSplits } from '../lib/cidr-splits'; + +describe('Cidr split results', () => { + test('3 big subnets then 6 small ones', () => { + expect(calculateCidrSplits(22, [24, 24, 24, 28, 28, 28, 28, 28, 28])).toEqual([ + { netmask: 24, count: 4, index: 0 }, + { netmask: 24, count: 4, index: 1 }, + { netmask: 24, count: 4, index: 2 }, + { netmask: 28, count: 64, index: 48 }, + { netmask: 28, count: 64, index: 49 }, + { netmask: 28, count: 64, index: 50 }, + { netmask: 28, count: 64, index: 51 }, + { netmask: 28, count: 64, index: 52 }, + { netmask: 28, count: 64, index: 53 }, + ]); + }); + + test('3 small subnets then 2 big ones', () => { + expect(calculateCidrSplits(22, [27, 27, 27, 24, 24])).toEqual([ + { netmask: 27, count: 32, index: 0 }, + { netmask: 27, count: 32, index: 1 }, + { netmask: 27, count: 32, index: 2 }, + { netmask: 24, count: 4, index: 1 }, + { netmask: 24, count: 4, index: 2 }, + ]); + }); + + test('small big small', () => { + expect (calculateCidrSplits(22, [28, 24, 28])).toEqual([ + { netmask: 28, count: 64, index: 0 }, + { netmask: 24, count: 4, index: 1 }, + { netmask: 28, count: 64, index: 32 }, + ]); + }); + + test('allocation too big', () => { + expect(() => calculateCidrSplits(22, [23, 23, 23])).toThrow(/not big enough/); + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts new file mode 100644 index 0000000000000..06ab7accbd9b5 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts @@ -0,0 +1,84 @@ +import * as cdk from '@aws-cdk/core'; +import { AwsCustomResource, PhysicalResourceId, AwsCustomResourcePolicy } from '@aws-cdk/custom-resources'; +import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests'; +import { AwsIpam, CfnIPAM, CfnIPAMPool, CfnVPC, SubnetType, Vpc } from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-ec2-ipam-vpc'); + +const ipam = new CfnIPAM(stack, 'IPAM', { + operatingRegions: [ + { regionName: stack.region }, + ], + tags: [{ + key: 'stack', + value: stack.stackId, + }], +}); +ipam.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN); + +const pool = new CfnIPAMPool(stack, 'Pool', { + description: 'Testing pool', + addressFamily: 'ipv4', + autoImport: false, + locale: stack.region, + ipamScopeId: ipam.attrPrivateDefaultScopeId, + provisionedCidrs: [{ + cidr: '100.100.0.0/16', + }], +}); +pool.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN); + +const awsIpamVpc = new Vpc(stack, 'AwsIpamVpc', { + ipamProvider: new AwsIpam({ + ipv4IpamPoolId: pool.ref, + ipv4NetmaskLength: 18, + defaultSubnetIpv4NetmaskLength: 24, + }), + maxAzs: 2, + subnetConfiguration: [{ + name: 'private', + subnetType: SubnetType.PRIVATE_ISOLATED, + cidrMask: 24, + }], +}); + +new AwsCustomResource(stack, 'cleanUpIpam', { // Cleanup as the IPAM does not delete otherwise, must use aws-sdk-js2 newer than: 1094.0 + installLatestAwsSdk: true, + onCreate: { + service: 'EC2', + action: 'deleteIpam', + parameters: { + IpamId: ipam.getAtt('IpamId').toString(), + Cascade: true, + }, + physicalResourceId: PhysicalResourceId.of('cleanUpIpam'), + }, + + policy: AwsCustomResourcePolicy.fromSdkCalls({ + resources: AwsCustomResourcePolicy.ANY_RESOURCE, + }), +}).node.addDependency(awsIpamVpc); + + +/** + * Testing That the Vpc is Deployed with the correct Cidrs. +**/ +const integ = new IntegTest(app, 'Vpc-Ipam', { + testCases: [stack], + allowDestroy: ['EC2::IPAM'], +}); + +integ.assertions.awsApiCall('EC2', 'describeVpcs', { + VpcIds: [(awsIpamVpc.node.defaultChild as CfnVPC).getAtt('VpcId').toString()], +}).expect(ExpectedResult.objectLike({ + "Vpcs": [ + { + "CidrBlock": "100.100.0.0/18", + } + ] +})); + +app.synth(); + + diff --git a/packages/@aws-cdk/aws-ec2/test/ipam.test.ts b/packages/@aws-cdk/aws-ec2/test/ipam.test.ts new file mode 100644 index 0000000000000..1b75741261632 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/ipam.test.ts @@ -0,0 +1,410 @@ +import { Template } from '@aws-cdk/assertions'; +import { Stack } from '@aws-cdk/core'; +import { AwsIpam, IpamProvider, StaticIpam, SubnetType, Vpc } from '../lib'; + +describe('StaticIpam vpc allocation', () => { + + test('Default StaticIpam returns the correct vpc cidr', () => { + const ipamProvider = new StaticIpam('10.0.0.0/16'); + expect(ipamProvider.allocateVpcCidr().cidrBlock).toEqual('10.0.0.0/16'); + }); + + test('Default StaticIpam returns ipv4IpamPoolId as undefined', () => { + const ipamProvider = new StaticIpam('10.0.0.0/16'); + expect(ipamProvider.allocateVpcCidr().ipv4IpamPoolId).toBeUndefined; + }); + + test('Default StaticIpam returns ipv4NetmaskLength as undefined', () => { + const ipamProvider = new StaticIpam('10.0.0.0/16'); + expect(ipamProvider.allocateVpcCidr().ipv4NetmaskLength).toBeUndefined; + }); + +}); + +describe('StaticIpam subnets allocation', () => { + + const staticIpamProps = '10.0.0.0/16'; + + test('Default StaticIpam returns the correct subnet allocations, when you do not give a cidr for the subnets', () => { + const ipamProvider = new StaticIpam(staticIpamProps); + expect(ipamProvider.allocateSubnetsCidr({ + requestedSubnets: [{ + availabilityZone: 'dummyAz1', + configuration: { + name: 'public', + subnetType: SubnetType.PUBLIC, + }, + subnetConstructId: 'public', + }, { + availabilityZone: 'dummyAz1', + configuration: { + name: 'private-with-egress', + subnetType: SubnetType.PRIVATE_WITH_EGRESS, + }, + subnetConstructId: 'public', + }], + vpcCidr: '10.0.0.0/16', + }).allocatedSubnets).toEqual([{ cidr: '10.0.0.0/17' }, { cidr: '10.0.128.0/17' }]); + }); + + test('Default StaticIpam returns the correct subnet allocations, when you provide a cidr for the subnets', () => { + const ipamProvider = new StaticIpam(staticIpamProps); + expect(ipamProvider.allocateSubnetsCidr({ + requestedSubnets: [{ + availabilityZone: 'dummyAz1', + configuration: { + name: 'public', + subnetType: SubnetType.PUBLIC, + cidrMask: 24, + }, + subnetConstructId: 'public', + }, { + availabilityZone: 'dummyAz1', + configuration: { + name: 'private-with-egress', + subnetType: SubnetType.PRIVATE_WITH_EGRESS, + cidrMask: 24, + }, + subnetConstructId: 'public', + }], + vpcCidr: '10.0.0.0/16', + }).allocatedSubnets).toEqual([{ cidr: '10.0.0.0/24' }, { cidr: '10.0.1.0/24' }]); + }); + + test('Default StaticIpam returns the correct subnet allocations, when you mix provide and non provided cidr for the subnets', () => { + const ipamProvider = new StaticIpam(staticIpamProps); + expect(ipamProvider.allocateSubnetsCidr({ + requestedSubnets: [{ + availabilityZone: 'dummyAz1', + configuration: { + name: 'public', + subnetType: SubnetType.PUBLIC, + }, + subnetConstructId: 'public', + }, { + availabilityZone: 'dummyAz1', + configuration: { + name: 'private-with-egress', + subnetType: SubnetType.PRIVATE_WITH_EGRESS, + cidrMask: 24, + }, + subnetConstructId: 'public', + }], + vpcCidr: '10.0.0.0/16', + }).allocatedSubnets).toEqual([{ cidr: '10.0.128.0/17' }, { cidr: '10.0.0.0/24' }]); + }); + +}); + +describe('AwsIpam vpc allocation', () => { + + const awsIpamProps = { + ipv4IpamPoolId: 'ipam-pool-0111222333444', + ipv4NetmaskLength: 22, + }; + + test('AwsIpam returns cidrBlock as undefined', () => { + const ipamProvider = new AwsIpam(awsIpamProps); + expect(ipamProvider.allocateVpcCidr().cidrBlock).toBeUndefined; + }); + + test('AwsIpam returns the correct vpc ipv4IpamPoolId', () => { + const ipamProvider = new AwsIpam(awsIpamProps); + expect(ipamProvider.allocateVpcCidr().ipv4IpamPoolId).toEqual('ipam-pool-0111222333444'); + }); + + test('AwsIpam returns the correct vpc ipv4NetmaskLength', () => { + const ipamProvider = new AwsIpam(awsIpamProps); + expect(ipamProvider.allocateVpcCidr().ipv4NetmaskLength).toEqual(22); + }); + +}); + +describe('AwsIpam subnets allocation', () => { + + const awsIpamProps = { + ipv4IpamPoolId: 'ipam-pool-0111222333444', + ipv4NetmaskLength: 22, + }; + + test('AwsIpam returns subnet allocations as 2x TOKEN, when you do not give a cidr for the subnets', () => { + const ipamProvider = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const allocations = ipamProvider.allocateSubnetsCidr({ + requestedSubnets: [{ + availabilityZone: 'dummyAz1', + configuration: { + name: 'public', + subnetType: SubnetType.PUBLIC, + }, + subnetConstructId: 'public', + }, { + availabilityZone: 'dummyAz1', + configuration: { + name: 'private-with-egress', + subnetType: SubnetType.PRIVATE_WITH_EGRESS, + }, + subnetConstructId: 'public', + }], + vpcCidr: '10.0.0.0/16', + }); + + expect (allocations.allocatedSubnets.length).toBe(2); + expect (allocations.allocatedSubnets[0].cidr).toContain('TOKEN'); + expect (allocations.allocatedSubnets[1].cidr).toContain('TOKEN'); + }); + + test('AwsIpam returns subnet allocations as 2x TOKEN, when you provide a cidr for the subnets', () => { + const ipamProvider = new AwsIpam(awsIpamProps); + const allocations = ipamProvider.allocateSubnetsCidr({ + requestedSubnets: [{ + availabilityZone: 'dummyAz1', + configuration: { + name: 'public', + subnetType: SubnetType.PUBLIC, + cidrMask: 24, + }, + subnetConstructId: 'public', + }, { + availabilityZone: 'dummyAz1', + configuration: { + name: 'private-with-egress', + subnetType: SubnetType.PRIVATE_WITH_EGRESS, + cidrMask: 24, + }, + subnetConstructId: 'public', + }], + vpcCidr: '10.0.0.0/16', + }); + + expect (allocations.allocatedSubnets.length).toBe(2); + expect (allocations.allocatedSubnets[0].cidr).toContain('TOKEN'); + expect (allocations.allocatedSubnets[1].cidr).toContain('TOKEN'); + }); + + test('AwsIpam returns subnet allocations as 2x TOKEN, when you mix provide and non provided cidr for the subnets', () => { + const ipamProvider = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const allocations = ipamProvider.allocateSubnetsCidr({ + requestedSubnets: [{ + availabilityZone: 'dummyAz1', + configuration: { + name: 'public', + subnetType: SubnetType.PUBLIC, + }, + subnetConstructId: 'public', + }, { + availabilityZone: 'dummyAz1', + configuration: { + name: 'private-with-egress', + subnetType: SubnetType.PRIVATE_WITH_EGRESS, + cidrMask: 24, + }, + subnetConstructId: 'public', + }], + vpcCidr: '10.0.0.0/16', + }); + + expect (allocations.allocatedSubnets.length).toBe(2); + expect (allocations.allocatedSubnets[0].cidr).toContain('TOKEN'); + expect (allocations.allocatedSubnets[1].cidr).toContain('TOKEN'); + }); + +}); + +describe('StaticIpam Vpc Integration', () => { + test('StaticIpam provides the correct Cidr allocation to the Vpc ', () => { + + const stack = new Stack(); + + const staticIpamProps = '10.0.0.0/16'; + const ipamProvider = IpamProvider.staticIpam(staticIpamProps); + + new Vpc(stack, 'VpcNetwork', { ipamProvider }); + + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { + CidrBlock: staticIpamProps, + }); + }); + + test('StaticIpam provides the correct Subnet allocation to the Vpc', () => { + + const stack = new Stack(); + + const staticIpamProps = '10.0.0.0/16'; + const ipamProvider = IpamProvider.staticIpam(staticIpamProps); + + new Vpc(stack, 'VpcNetwork', { ipamProvider }); + + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: '10.0.0.0/18', + }); + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: '10.0.64.0/18', + }); + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: '10.0.128.0/18', + }); + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: '10.0.192.0/18', + }); + }); +}); + +describe('AwsIpam Vpc Integration', () => { + + test('Should throw if there are subnets without explicit Cidr and no defaultCidr given', () => { + + const stack = new Stack(); + + const awsIpamProps = { + ipv4IpamPoolId: 'ipam-pool-0111222333444', + ipv4NetmaskLength: 22, + }; + + const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + + expect(() => {new Vpc(stack, 'VpcNetwork', { ipamProvider });}).toThrow(/If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in the provider/);; + + }); + + test('AwsIpam provides the correct Cidr allocation to the Vpc ', () => { + + const stack = new Stack(); + + const awsIpamProps = { + ipv4IpamPoolId: 'ipam-pool-0111222333444', + ipv4NetmaskLength: 22, + defaultSubnetIpv4NetmaskLength: 24, + }; + + const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + + new Vpc(stack, 'VpcNetwork', { ipamProvider }); + + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { + Ipv4IpamPoolId: awsIpamProps.ipv4IpamPoolId, + Ipv4NetmaskLength: awsIpamProps.ipv4NetmaskLength, + }); + }); + + + test('AwsIpam provides the correct Subnet allocation to the Vpc', () => { + + const stack = new Stack(); + + const awsIpamProps = { + ipv4IpamPoolId: 'ipam-pool-0111222333444', + ipv4NetmaskLength: 22, + defaultSubnetIpv4NetmaskLength: 24, + }; + + const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + + new Vpc(stack, 'VpcNetwork', { ipamProvider }); + + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: { + 'Fn::Select': [0, { + 'Fn::Cidr': [{ + 'Fn::GetAtt': ['VpcNetworkB258E83A', 'CidrBlock'], + }, 4, '8'], + }], + }, + }); + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: { + 'Fn::Select': [1, { + 'Fn::Cidr': [{ + 'Fn::GetAtt': ['VpcNetworkB258E83A', 'CidrBlock'], + }, 4, '8'], + }], + }, + }); + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: { + 'Fn::Select': [2, { + 'Fn::Cidr': [{ + 'Fn::GetAtt': ['VpcNetworkB258E83A', 'CidrBlock'], + }, 4, '8'], + }], + }, + }); + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: { + 'Fn::Select': [3, { + 'Fn::Cidr': [{ + 'Fn::GetAtt': ['VpcNetworkB258E83A', 'CidrBlock'], + }, 4, '8'], + }], + }, + }); + }); + + test('Should throw if ipv4NetmaskLength not big enough to allocate subnets', () => { + + const stack = new Stack(); + + const awsIpamProps = { + ipv4IpamPoolId: 'ipam-pool-0111222333444', + ipv4NetmaskLength: 18, + defaultSubnetIpv4NetmaskLength: 17, + }; + + const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + + expect(() => {new Vpc(stack, 'VpcNetwork', { ipamProvider });}).toThrow('IP space of size /18 not big enough to allocate subnets of sizes /17,/17,/17,/17');; + + }); + + test('Should be able to allocate subnets from a SubnetConfiguration in Vpc Constructor', () => { + + const stack = new Stack(); + + const awsIpamProps = { + ipv4IpamPoolId: 'ipam-pool-0111222333444', + ipv4NetmaskLength: 18, + defaultSubnetIpv4NetmaskLength: 17, + }; + + const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + + new Vpc(stack, 'VpcNetwork', { + ipamProvider, + subnetConfiguration: [{ + name: 'public', + subnetType: SubnetType.PUBLIC, + cidrMask: 24, + }], + maxAzs: 2, + }); + + const template = Template.fromStack(stack); + + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: { + 'Fn::Select': [0, { + 'Fn::Cidr': [{ + 'Fn::GetAtt': ['VpcNetworkB258E83A', 'CidrBlock'], + }, 64, '8'], + }], + }, + }); + + template.hasResourceProperties('AWS::EC2::Subnet', { + CidrBlock: { + 'Fn::Select': [1, { + 'Fn::Cidr': [{ + 'Fn::GetAtt': ['VpcNetworkB258E83A', 'CidrBlock'], + }, 64, '8'], + }], + }, + }); + + template.resourceCountIs('AWS::EC2::Subnet', 2); + + }); + +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index e5ae1a6ed00cc..4fd566f7f1e01 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -410,19 +410,22 @@ describe('vpc', () => { ], maxAzs: 3, }); + + const template = Template.fromStack(stack); + for (let i = 0; i < 3; i++) { - Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { + template.hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.${i}.0/24`, }); } for (let i = 3; i < 6; i++) { - const matchingSubnets = Template.fromStack(stack).findResources('AWS::EC2::Subnet', { + const matchingSubnets = template.findResources('AWS::EC2::Subnet', { CidrBlock: `10.0.${i}.0/24`, }); expect(Object.keys(matchingSubnets).length).toBe(0); } for (let i = 6; i < 9; i++) { - Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', { + template.hasResourceProperties('AWS::EC2::Subnet', { CidrBlock: `10.0.${i}.0/24`, }); } From 9e3fd7ec1f8747e395a56abbe94ad6a9f67dce73 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 10 Oct 2022 09:58:41 +0100 Subject: [PATCH 02/20] WIP --- .../@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts | 50 +- ...efaultTestDeployAssertB1CA1C3A.assets.json | 32 + ...aultTestDeployAssertB1CA1C3A.template.json | 135 ++++ .../index.js | 687 ++++++++++++++++++ .../aws-cdk-ec2-ipam-vpc.assets.json | 32 + .../aws-cdk-ec2-ipam-vpc.template.json | 349 +++++++++ .../test/vpc-ipam.integ.snapshot/cdk.out | 1 + .../test/vpc-ipam.integ.snapshot/integ.json | 15 + .../vpc-ipam.integ.snapshot/manifest.json | 208 ++++++ .../test/vpc-ipam.integ.snapshot/tree.json | 579 +++++++++++++++ 10 files changed, 2068 insertions(+), 20 deletions(-) create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle/index.js create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.assets.json create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.template.json create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/tree.json diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts index 06ab7accbd9b5..8691d3bfe5533 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts @@ -1,6 +1,6 @@ import * as cdk from '@aws-cdk/core'; -import { AwsCustomResource, PhysicalResourceId, AwsCustomResourcePolicy } from '@aws-cdk/custom-resources'; -import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests'; +// import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources'; +import { ExpectedResult, IntegTest, AwsApiCall } from '@aws-cdk/integ-tests'; import { AwsIpam, CfnIPAM, CfnIPAMPool, CfnVPC, SubnetType, Vpc } from '../lib'; const app = new cdk.App(); @@ -43,22 +43,32 @@ const awsIpamVpc = new Vpc(stack, 'AwsIpamVpc', { }], }); -new AwsCustomResource(stack, 'cleanUpIpam', { // Cleanup as the IPAM does not delete otherwise, must use aws-sdk-js2 newer than: 1094.0 +new AwsApiCall(stack, 'cleanUpIpam', { + service: 'EC2', + api: 'deleteIpam', installLatestAwsSdk: true, - onCreate: { - service: 'EC2', - action: 'deleteIpam', - parameters: { - IpamId: ipam.getAtt('IpamId').toString(), - Cascade: true, - }, - physicalResourceId: PhysicalResourceId.of('cleanUpIpam'), + parameters: { + IpamId: ipam.attrIpamId, + Cascade: true, }, +}); - policy: AwsCustomResourcePolicy.fromSdkCalls({ - resources: AwsCustomResourcePolicy.ANY_RESOURCE, - }), -}).node.addDependency(awsIpamVpc); +// new AwsCustomResource(stack, 'cleanUpIpam', { // Cleanup as the IPAM does not delete otherwise, must use aws-sdk-js2 newer than: 1094.0 +// installLatestAwsSdk: true, +// onCreate: { +// service: 'EC2', +// action: 'deleteIpam', +// parameters: { +// IpamId: ipam.getAtt('IpamId').toString(), +// Cascade: true, +// }, +// physicalResourceId: PhysicalResourceId.of('cleanUpIpam'), +// }, + +// policy: AwsCustomResourcePolicy.fromSdkCalls({ +// resources: AwsCustomResourcePolicy.ANY_RESOURCE, +// }), +// }).node.addDependency(awsIpamVpc); /** @@ -72,11 +82,11 @@ const integ = new IntegTest(app, 'Vpc-Ipam', { integ.assertions.awsApiCall('EC2', 'describeVpcs', { VpcIds: [(awsIpamVpc.node.defaultChild as CfnVPC).getAtt('VpcId').toString()], }).expect(ExpectedResult.objectLike({ - "Vpcs": [ - { - "CidrBlock": "100.100.0.0/18", - } - ] + Vpcs: [ + { + CidrBlock: '100.100.0.0/18', + }, + ], })); app.synth(); diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json new file mode 100644 index 0000000000000..b7f477b027c1a --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json @@ -0,0 +1,32 @@ +{ + "version": "21.0.0", + "files": { + "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd": { + "source": { + "path": "asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "82bad81cf8eac60f0e51fc423dae939f8eeeeebef3c4bae147061066e0314098": { + "source": { + "path": "VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "82bad81cf8eac60f0e51fc423dae939f8eeeeebef3c4bae147061066e0314098.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json new file mode 100644 index 0000000000000..69202e02f7710 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json @@ -0,0 +1,135 @@ +{ + "Resources": { + "AwsApiCallEC2describeVpcs": { + "Type": "Custom::DeployAssert@SdkCallEC2describeVpcs", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "EC2", + "api": "describeVpcs", + "expected": "{\"$ObjectLike\":{\"Vpcs\":[{\"CidrBlock\":\"100.100.0.0/18\"}]}}", + "parameters": { + "VpcIds": [ + { + "Fn::ImportValue": "aws-cdk-ec2-ipam-vpc:ExportsOutputFnGetAttAwsIpamVpcD3A1DAEEVpcId808CC597" + } + ] + }, + "flattenResponse": "false", + "salt": "1665391872401", + "installLatestAwsSdk": false + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "ec2:DescribeVpcs" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "AssertionResultsAwsApiCallEC2describeVpcs": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallEC2describeVpcs", + "assertion" + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle/index.js b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle/index.js new file mode 100644 index 0000000000000..184c7f6ac442d --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle/index.js @@ -0,0 +1,687 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// lib/assertions/providers/lambda-handler/index.ts +var lambda_handler_exports = {}; +__export(lambda_handler_exports, { + handler: () => handler +}); +module.exports = __toCommonJS(lambda_handler_exports); + +// ../assertions/lib/matcher.ts +var Matcher = class { + static isMatcher(x) { + return x && x instanceof Matcher; + } +}; +var MatchResult = class { + constructor(target) { + this.failures = []; + this.captures = /* @__PURE__ */ new Map(); + this.finalized = false; + this.target = target; + } + push(matcher, path, message) { + return this.recordFailure({ matcher, path, message }); + } + recordFailure(failure) { + this.failures.push(failure); + return this; + } + hasFailed() { + return this.failures.length !== 0; + } + get failCount() { + return this.failures.length; + } + compose(id, inner) { + const innerF = inner.failures; + this.failures.push(...innerF.map((f) => { + return { path: [id, ...f.path], message: f.message, matcher: f.matcher }; + })); + inner.captures.forEach((vals, capture) => { + vals.forEach((value) => this.recordCapture({ capture, value })); + }); + return this; + } + finished() { + if (this.finalized) { + return this; + } + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; + return this; + } + toHumanStrings() { + return this.failures.map((r) => { + const loc = r.path.length === 0 ? "" : ` at ${r.path.join("")}`; + return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; + }); + } + recordCapture(options) { + let values = this.captures.get(options.capture); + if (values === void 0) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } +}; + +// ../assertions/lib/private/matchers/absent.ts +var AbsentMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual !== void 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent` + }); + } + return result; + } +}; + +// ../assertions/lib/private/type.ts +function getType(obj) { + return Array.isArray(obj) ? "array" : typeof obj; +} + +// ../assertions/lib/match.ts +var Match = class { + static absent() { + return new AbsentMatch("absent"); + } + static arrayWith(pattern) { + return new ArrayMatch("arrayWith", pattern); + } + static arrayEquals(pattern) { + return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); + } + static exact(pattern) { + return new LiteralMatch("exact", pattern, { partialObjects: false }); + } + static objectLike(pattern) { + return new ObjectMatch("objectLike", pattern); + } + static objectEquals(pattern) { + return new ObjectMatch("objectEquals", pattern, { partial: false }); + } + static not(pattern) { + return new NotMatch("not", pattern); + } + static serializedJson(pattern) { + return new SerializedJson("serializedJson", pattern); + } + static anyValue() { + return new AnyMatch("anyValue"); + } + static stringLikeRegexp(pattern) { + return new StringLikeRegexpMatch("stringLikeRegexp", pattern); + } +}; +var LiteralMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partialObjects = options.partialObjects ?? false; + if (Matcher.isMatcher(this.pattern)) { + throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); + } + } + test(actual) { + if (Array.isArray(this.pattern)) { + return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); + } + if (typeof this.pattern === "object") { + return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); + } + const result = new MatchResult(actual); + if (typeof this.pattern !== typeof actual) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` + }); + return result; + } + if (actual !== this.pattern) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}` + }); + } + return result; + } +}; +var ArrayMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.subsequence = options.subsequence ?? true; + this.partialObjects = options.partialObjects ?? false; + } + test(actual) { + if (!Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}` + }); + } + if (!this.subsequence && this.pattern.length !== actual.length) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected array of length ${this.pattern.length} but received ${actual.length}` + }); + } + let patternIdx = 0; + let actualIdx = 0; + const result = new MatchResult(actual); + while (patternIdx < this.pattern.length && actualIdx < actual.length) { + const patternElement = this.pattern[patternIdx]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const matcherName = matcher.name; + if (this.subsequence && (matcherName == "absent" || matcherName == "anyValue")) { + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); + } + const innerResult = matcher.test(actual[actualIdx]); + if (!this.subsequence || !innerResult.hasFailed()) { + result.compose(`[${actualIdx}]`, innerResult); + patternIdx++; + actualIdx++; + } else { + actualIdx++; + } + } + for (; patternIdx < this.pattern.length; patternIdx++) { + const pattern = this.pattern[patternIdx]; + const element = Matcher.isMatcher(pattern) || typeof pattern === "object" ? " " : ` [${pattern}] `; + result.recordFailure({ + matcher: this, + path: [], + message: `Missing element${element}at pattern index ${patternIdx}` + }); + } + return result; + } +}; +var ObjectMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partial = options.partial ?? true; + } + test(actual) { + if (typeof actual !== "object" || Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}` + }); + } + const result = new MatchResult(actual); + if (!this.partial) { + for (const a of Object.keys(actual)) { + if (!(a in this.pattern)) { + result.recordFailure({ + matcher: this, + path: [`/${a}`], + message: "Unexpected key" + }); + } + } + } + for (const [patternKey, patternVal] of Object.entries(this.pattern)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { + result.recordFailure({ + matcher: this, + path: [`/${patternKey}`], + message: `Missing key '${patternKey}' among {${Object.keys(actual).join(",")}}` + }); + continue; + } + const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); + const inner = matcher.test(actual[patternKey]); + result.compose(`/${patternKey}`, inner); + } + return result; + } +}; +var SerializedJson = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + if (getType(actual) !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected JSON as a string but found ${getType(actual)}` + }); + return result; + } + let parsed; + try { + parsed = JSON.parse(actual); + } catch (err) { + if (err instanceof SyntaxError) { + result.recordFailure({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}` + }); + return result; + } else { + throw err; + } + } + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(parsed); + result.compose(`(${this.name})`, innerResult); + return result; + } +}; +var NotMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(actual); + const result = new MatchResult(actual); + if (innerResult.failCount === 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` + }); + } + return result; + } +}; +var AnyMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual == null) { + result.recordFailure({ + matcher: this, + path: [], + message: "Expected a value but found none" + }); + } + return result; + } +}; +var StringLikeRegexpMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + const regex = new RegExp(this.pattern, "gm"); + if (typeof actual !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'` + }); + } + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'` + }); + } + return result; + } +}; + +// lib/assertions/providers/lambda-handler/base.ts +var https = __toESM(require("https")); +var url = __toESM(require("url")); +var CustomResourceHandler = class { + constructor(event, context) { + this.event = event; + this.context = context; + this.timedOut = false; + this.timeout = setTimeout(async () => { + await this.respond({ + status: "FAILED", + reason: "Lambda Function Timeout", + data: this.context.logStreamName + }); + this.timedOut = true; + }, context.getRemainingTimeInMillis() - 1200); + this.event = event; + this.physicalResourceId = extractPhysicalResourceId(event); + } + async handle() { + try { + const response = await this.processEvent(this.event.ResourceProperties); + return response; + } catch (e) { + console.log(e); + throw e; + } finally { + clearTimeout(this.timeout); + } + } + respond(response) { + if (this.timedOut) { + return; + } + const cfResponse = { + Status: response.status, + Reason: response.reason, + PhysicalResourceId: this.physicalResourceId, + StackId: this.event.StackId, + RequestId: this.event.RequestId, + LogicalResourceId: this.event.LogicalResourceId, + NoEcho: false, + Data: response.data + }; + const responseBody = JSON.stringify(cfResponse); + console.log("Responding to CloudFormation", responseBody); + const parsedUrl = url.parse(this.event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: "PUT", + headers: { "content-type": "", "content-length": responseBody.length } + }; + return new Promise((resolve, reject) => { + try { + const request2 = https.request(requestOptions, resolve); + request2.on("error", reject); + request2.write(responseBody); + request2.end(); + } catch (e) { + reject(e); + } + }); + } +}; +function extractPhysicalResourceId(event) { + switch (event.RequestType) { + case "Create": + return event.LogicalResourceId; + case "Update": + case "Delete": + return event.PhysicalResourceId; + } +} + +// lib/assertions/providers/lambda-handler/assertion.ts +var AssertionHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let actual = decodeCall(request2.actual); + const expected = decodeCall(request2.expected); + let result; + const matcher = new MatchCreator(expected).getMatcher(); + console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); + const matchResult = matcher.test(actual); + matchResult.finished(); + if (matchResult.hasFailed()) { + result = { + failed: true, + assertion: JSON.stringify({ + status: "fail", + message: [ + ...matchResult.toHumanStrings(), + JSON.stringify(matchResult.target, void 0, 2) + ].join("\n") + }) + }; + if (request2.failDeployment) { + throw new Error(result.assertion); + } + } else { + result = { + assertion: JSON.stringify({ + status: "success" + }) + }; + } + return result; + } +}; +var MatchCreator = class { + constructor(obj) { + this.parsedObj = { + matcher: obj + }; + } + getMatcher() { + try { + const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { + const nested = Object.keys(v)[0]; + switch (nested) { + case "$ArrayWith": + return Match.arrayWith(v[nested]); + case "$ObjectLike": + return Match.objectLike(v[nested]); + case "$StringLike": + return Match.stringLikeRegexp(v[nested]); + default: + return v; + } + }); + if (Matcher.isMatcher(final.matcher)) { + return final.matcher; + } + return Match.exact(final.matcher); + } catch { + return Match.exact(this.parsedObj.matcher); + } + } +}; +function decodeCall(call) { + if (!call) { + return void 0; + } + try { + const parsed = JSON.parse(call); + return parsed; + } catch (e) { + return call; + } +} + +// lib/assertions/providers/lambda-handler/sdk.ts +var import_child_process = require("child_process"); + +// lib/assertions/providers/lambda-handler/utils.ts +function decode(object) { + return JSON.parse(JSON.stringify(object), (_k, v) => { + switch (v) { + case "TRUE:BOOLEAN": + return true; + case "FALSE:BOOLEAN": + return false; + default: + return v; + } + }); +} + +// lib/assertions/providers/lambda-handler/sdk.ts +function flatten(object) { + return Object.assign( + {}, + ...function _flatten(child, path = []) { + return [].concat(...Object.keys(child).map((key) => { + let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; + if (typeof childKey === "string") { + childKey = isJsonString(childKey); + } + return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; + })); + }(object) + ); +} +function installLatestSdk() { + console.log("Installing latest AWS SDK v2"); + (0, import_child_process.execSync)("HOME=/tmp npm install aws-sdk@2 --production --no-package-lock --no-save --prefix /tmp"); +} +var AwsApiCallHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let AWS; + if (request2.installLatestAwsSdk === "true") { + try { + installLatestSdk(); + AWS = require("/tmp/node_modules/aws-sdk"); + } catch (e) { + console.log(`Failed to install latest AWS SDK v2: ${e}`); + AWS = require("aws-sdk"); + } + } else { + AWS = require("aws-sdk"); + } + console.log(`AWS SDK VERSION: ${AWS.VERSION}`); + if (!Object.prototype.hasOwnProperty.call(AWS, request2.service)) { + throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS.VERSION}.`); + } + const service = new AWS[request2.service](); + const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); + console.log(`SDK response received ${JSON.stringify(response)}`); + delete response.ResponseMetadata; + const respond = { + apiCallResponse: response + }; + const flatData = { + ...flatten(respond) + }; + const resp = request2.flattenResponse === "true" ? flatData : respond; + console.log(`Returning result ${JSON.stringify(resp)}`); + return resp; + } +}; +function isJsonString(value) { + try { + return JSON.parse(value); + } catch { + return value; + } +} + +// lib/assertions/providers/lambda-handler/types.ts +var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; +var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; + +// lib/assertions/providers/lambda-handler/index.ts +async function handler(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + if (event.RequestType === "Delete") { + await provider.respond({ + status: "SUCCESS", + reason: "OK" + }); + return; + } + const result = await provider.handle(); + const actualPath = event.ResourceProperties.actualPath; + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + if ("expected" in event.ResourceProperties) { + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + try { + const assertionResult = await assertion.handle(); + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + return; +} +function createResourceHandler(event, context) { + if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { + return new AwsApiCallHandler(event, context); + } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { + return new AssertionHandler(event, context); + } else { + throw new Error(`Unsupported resource type "${event.ResourceType}`); + } +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + handler +}); diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.assets.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.assets.json new file mode 100644 index 0000000000000..e0c7241341957 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.assets.json @@ -0,0 +1,32 @@ +{ + "version": "21.0.0", + "files": { + "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd": { + "source": { + "path": "asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "d1725d3e6f9001532273823c6744d8c471e52954ff414ab9e83d5979a47f61a4": { + "source": { + "path": "aws-cdk-ec2-ipam-vpc.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "d1725d3e6f9001532273823c6744d8c471e52954ff414ab9e83d5979a47f61a4.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.template.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.template.json new file mode 100644 index 0000000000000..cecf8d15b2b0d --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.template.json @@ -0,0 +1,349 @@ +{ + "Resources": { + "IPAM": { + "Type": "AWS::EC2::IPAM", + "Properties": { + "OperatingRegions": [ + { + "RegionName": { + "Ref": "AWS::Region" + } + } + ], + "Tags": [ + { + "Key": "stack", + "Value": { + "Ref": "AWS::StackId" + } + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "Pool": { + "Type": "AWS::EC2::IPAMPool", + "Properties": { + "AddressFamily": "ipv4", + "IpamScopeId": { + "Fn::GetAtt": [ + "IPAM", + "PrivateDefaultScopeId" + ] + }, + "AutoImport": false, + "Description": "Testing pool", + "Locale": { + "Ref": "AWS::Region" + }, + "ProvisionedCidrs": [ + { + "Cidr": "100.100.0.0/16" + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "AwsIpamVpcD3A1DAEE": { + "Type": "AWS::EC2::VPC", + "Properties": { + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Ipv4IpamPoolId": { + "Ref": "Pool" + }, + "Ipv4NetmaskLength": 18, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc" + } + ] + } + }, + "AwsIpamVpcprivateSubnet1Subnet0AC8649F": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "AwsIpamVpcD3A1DAEE" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": { + "Fn::Select": [ + 0, + { + "Fn::Cidr": [ + { + "Fn::GetAtt": [ + "AwsIpamVpcD3A1DAEE", + "CidrBlock" + ] + }, + 64, + "8" + ] + } + ] + }, + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1" + } + ] + } + }, + "AwsIpamVpcprivateSubnet1RouteTable2A97E440": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "AwsIpamVpcD3A1DAEE" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1" + } + ] + } + }, + "AwsIpamVpcprivateSubnet1RouteTableAssociationE7D2E570": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "AwsIpamVpcprivateSubnet1RouteTable2A97E440" + }, + "SubnetId": { + "Ref": "AwsIpamVpcprivateSubnet1Subnet0AC8649F" + } + } + }, + "AwsIpamVpcprivateSubnet2Subnet577660DE": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "AwsIpamVpcD3A1DAEE" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": { + "Fn::Select": [ + 1, + { + "Fn::Cidr": [ + { + "Fn::GetAtt": [ + "AwsIpamVpcD3A1DAEE", + "CidrBlock" + ] + }, + 64, + "8" + ] + } + ] + }, + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2" + } + ] + } + }, + "AwsIpamVpcprivateSubnet2RouteTableDDE2D1BF": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "AwsIpamVpcD3A1DAEE" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2" + } + ] + } + }, + "AwsIpamVpcprivateSubnet2RouteTableAssociation52A3C85A": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "AwsIpamVpcprivateSubnet2RouteTableDDE2D1BF" + }, + "SubnetId": { + "Ref": "AwsIpamVpcprivateSubnet2Subnet577660DE" + } + } + }, + "cleanUpIpam": { + "Type": "Custom::DeployAssert@SdkCallEC2deleteIpam", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "EC2", + "api": "deleteIpam", + "parameters": { + "IpamId": { + "Fn::GetAtt": [ + "IPAM", + "IpamId" + ] + }, + "Cascade": "TRUE:BOOLEAN" + }, + "flattenResponse": "false", + "salt": "1665391872399", + "installLatestAwsSdk": true + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "ec2:DeleteIpam" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "ExportsOutputFnGetAttAwsIpamVpcD3A1DAEEVpcId808CC597": { + "Value": { + "Fn::GetAtt": [ + "AwsIpamVpcD3A1DAEE", + "VpcId" + ] + }, + "Export": { + "Name": "aws-cdk-ec2-ipam-vpc:ExportsOutputFnGetAttAwsIpamVpcD3A1DAEEVpcId808CC597" + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..8ecc185e9dbee --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/integ.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/integ.json new file mode 100644 index 0000000000000..158faa819fea8 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/integ.json @@ -0,0 +1,15 @@ +{ + "version": "21.0.0", + "testCases": { + "Vpc-Ipam/DefaultTest": { + "stacks": [ + "aws-cdk-ec2-ipam-vpc" + ], + "allowDestroy": [ + "EC2::IPAM" + ], + "assertionStack": "Vpc-Ipam/DefaultTest/DeployAssert", + "assertionStackName": "VpcIpamDefaultTestDeployAssertB1CA1C3A" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..3ae93500bd78f --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/manifest.json @@ -0,0 +1,208 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-ec2-ipam-vpc.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-ec2-ipam-vpc.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-ec2-ipam-vpc": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-ec2-ipam-vpc.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/d1725d3e6f9001532273823c6744d8c471e52954ff414ab9e83d5979a47f61a4.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-ec2-ipam-vpc.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-ec2-ipam-vpc.assets" + ], + "metadata": { + "/aws-cdk-ec2-ipam-vpc/IPAM": [ + { + "type": "aws:cdk:logicalId", + "data": "IPAM" + } + ], + "/aws-cdk-ec2-ipam-vpc/Pool": [ + { + "type": "aws:cdk:logicalId", + "data": "Pool" + } + ], + "/aws-cdk-ec2-ipam-vpc/AwsIpamVpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsIpamVpcD3A1DAEE" + } + ], + "/aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsIpamVpcprivateSubnet1Subnet0AC8649F" + } + ], + "/aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsIpamVpcprivateSubnet1RouteTable2A97E440" + } + ], + "/aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsIpamVpcprivateSubnet1RouteTableAssociationE7D2E570" + } + ], + "/aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsIpamVpcprivateSubnet2Subnet577660DE" + } + ], + "/aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsIpamVpcprivateSubnet2RouteTableDDE2D1BF" + } + ], + "/aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsIpamVpcprivateSubnet2RouteTableAssociation52A3C85A" + } + ], + "/aws-cdk-ec2-ipam-vpc/cleanUpIpam/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "cleanUpIpam" + } + ], + "/aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/aws-cdk-ec2-ipam-vpc/Exports/Output{\"Fn::GetAtt\":[\"AwsIpamVpcD3A1DAEE\",\"VpcId\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttAwsIpamVpcD3A1DAEEVpcId808CC597" + } + ], + "/aws-cdk-ec2-ipam-vpc/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-ec2-ipam-vpc/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-ec2-ipam-vpc" + }, + "VpcIpamDefaultTestDeployAssertB1CA1C3A.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "VpcIpamDefaultTestDeployAssertB1CA1C3A": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/82bad81cf8eac60f0e51fc423dae939f8eeeeebef3c4bae147061066e0314098.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "VpcIpamDefaultTestDeployAssertB1CA1C3A.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-ec2-ipam-vpc", + "VpcIpamDefaultTestDeployAssertB1CA1C3A.assets" + ], + "metadata": { + "/Vpc-Ipam/DefaultTest/DeployAssert/AwsApiCallEC2describeVpcs/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallEC2describeVpcs" + } + ], + "/Vpc-Ipam/DefaultTest/DeployAssert/AwsApiCallEC2describeVpcs/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallEC2describeVpcs" + } + ], + "/Vpc-Ipam/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/Vpc-Ipam/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/Vpc-Ipam/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Vpc-Ipam/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Vpc-Ipam/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/tree.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/tree.json new file mode 100644 index 0000000000000..5a6d5ceca4b59 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/tree.json @@ -0,0 +1,579 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + }, + "aws-cdk-ec2-ipam-vpc": { + "id": "aws-cdk-ec2-ipam-vpc", + "path": "aws-cdk-ec2-ipam-vpc", + "children": { + "IPAM": { + "id": "IPAM", + "path": "aws-cdk-ec2-ipam-vpc/IPAM", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::IPAM", + "aws:cdk:cloudformation:props": { + "operatingRegions": [ + { + "regionName": { + "Ref": "AWS::Region" + } + } + ], + "tags": [ + { + "key": "stack", + "value": { + "Ref": "AWS::StackId" + } + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Pool": { + "id": "Pool", + "path": "aws-cdk-ec2-ipam-vpc/Pool", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::IPAMPool", + "aws:cdk:cloudformation:props": { + "addressFamily": "ipv4", + "ipamScopeId": { + "Fn::GetAtt": [ + "IPAM", + "PrivateDefaultScopeId" + ] + }, + "autoImport": false, + "description": "Testing pool", + "locale": { + "Ref": "AWS::Region" + }, + "provisionedCidrs": [ + { + "cidr": "100.100.0.0/16" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "AwsIpamVpc": { + "id": "AwsIpamVpc", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "ipv4IpamPoolId": { + "Ref": "Pool" + }, + "ipv4NetmaskLength": 18, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "privateSubnet1": { + "id": "privateSubnet1", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "AwsIpamVpcD3A1DAEE" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": { + "Fn::Select": [ + 0, + { + "Fn::Cidr": [ + { + "Fn::GetAtt": [ + "AwsIpamVpcD3A1DAEE", + "CidrBlock" + ] + }, + 64, + "8" + ] + } + ] + }, + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "AwsIpamVpcD3A1DAEE" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "AwsIpamVpcprivateSubnet1RouteTable2A97E440" + }, + "subnetId": { + "Ref": "AwsIpamVpcprivateSubnet1Subnet0AC8649F" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "privateSubnet2": { + "id": "privateSubnet2", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "AwsIpamVpcD3A1DAEE" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": { + "Fn::Select": [ + 1, + { + "Fn::Cidr": [ + { + "Fn::GetAtt": [ + "AwsIpamVpcD3A1DAEE", + "CidrBlock" + ] + }, + 64, + "8" + ] + } + ] + }, + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "AwsIpamVpcD3A1DAEE" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-ec2-ipam-vpc/AwsIpamVpc/privateSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "AwsIpamVpcprivateSubnet2RouteTableDDE2D1BF" + }, + "subnetId": { + "Ref": "AwsIpamVpcprivateSubnet2Subnet577660DE" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "cleanUpIpam": { + "id": "cleanUpIpam", + "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam/Default", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + }, + "Exports": { + "id": "Exports", + "path": "aws-cdk-ec2-ipam-vpc/Exports", + "children": { + "Output{\"Fn::GetAtt\":[\"AwsIpamVpcD3A1DAEE\",\"VpcId\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"AwsIpamVpcD3A1DAEE\",\"VpcId\"]}", + "path": "aws-cdk-ec2-ipam-vpc/Exports/Output{\"Fn::GetAtt\":[\"AwsIpamVpcD3A1DAEE\",\"VpcId\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "Vpc-Ipam": { + "id": "Vpc-Ipam", + "path": "Vpc-Ipam", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "Vpc-Ipam/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "Vpc-Ipam/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "Vpc-Ipam/DefaultTest/DeployAssert", + "children": { + "AwsApiCallEC2describeVpcs": { + "id": "AwsApiCallEC2describeVpcs", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/AwsApiCallEC2describeVpcs", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/AwsApiCallEC2describeVpcs/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/AwsApiCallEC2describeVpcs/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/AwsApiCallEC2describeVpcs/Default", + "children": { + "Default": { + "id": "Default", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/AwsApiCallEC2describeVpcs/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/AwsApiCallEC2describeVpcs/AssertionResults", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "Vpc-Ipam/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.123" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file From 283812f77b40f9e6630347c828327f31f50106b6 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Tue, 11 Oct 2022 09:14:28 +0100 Subject: [PATCH 03/20] remove blocking issue from integ-test for now --- .../@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts | 36 +++++-------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts index 8691d3bfe5533..d44b266f137aa 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts @@ -1,6 +1,5 @@ import * as cdk from '@aws-cdk/core'; -// import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources'; -import { ExpectedResult, IntegTest, AwsApiCall } from '@aws-cdk/integ-tests'; +import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests'; import { AwsIpam, CfnIPAM, CfnIPAMPool, CfnVPC, SubnetType, Vpc } from '../lib'; const app = new cdk.App(); @@ -43,33 +42,16 @@ const awsIpamVpc = new Vpc(stack, 'AwsIpamVpc', { }], }); -new AwsApiCall(stack, 'cleanUpIpam', { - service: 'EC2', - api: 'deleteIpam', - installLatestAwsSdk: true, - parameters: { - IpamId: ipam.attrIpamId, - Cascade: true, - }, -}); - -// new AwsCustomResource(stack, 'cleanUpIpam', { // Cleanup as the IPAM does not delete otherwise, must use aws-sdk-js2 newer than: 1094.0 +// needs AwsApiCall Support for installLatestAwsSdk first, or another way to clean the Ipam +// new AwsApiCall(stack, 'cleanUpIpam', { +// service: 'EC2', +// api: 'deleteIpam', // installLatestAwsSdk: true, -// onCreate: { -// service: 'EC2', -// action: 'deleteIpam', -// parameters: { -// IpamId: ipam.getAtt('IpamId').toString(), -// Cascade: true, -// }, -// physicalResourceId: PhysicalResourceId.of('cleanUpIpam'), +// parameters: { +// IpamId: ipam.attrIpamId, +// Cascade: true, // }, - -// policy: AwsCustomResourcePolicy.fromSdkCalls({ -// resources: AwsCustomResourcePolicy.ANY_RESOURCE, -// }), -// }).node.addDependency(awsIpamVpc); - +// }); /** * Testing That the Vpc is Deployed with the correct Cidrs. From 3bb5555c5b2cd606dd102ef08c1ad6d692911e33 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 24 Oct 2022 10:03:58 +0100 Subject: [PATCH 04/20] update based on comments from review --- packages/@aws-cdk/aws-ec2/README.md | 61 ++++++++-- packages/@aws-cdk/aws-ec2/lib/ipam.ts | 20 ++-- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 18 +-- .../@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts | 9 +- packages/@aws-cdk/aws-ec2/test/ipam.test.ts | 109 +++++++++--------- ...efaultTestDeployAssertB1CA1C3A.assets.json | 10 +- ...aultTestDeployAssertB1CA1C3A.template.json | 5 +- .../index.js | 20 +--- .../aws-cdk-ec2-ipam-vpc.assets.json | 17 +-- .../aws-cdk-ec2-ipam-vpc.template.json | 88 -------------- .../vpc-ipam.integ.snapshot/manifest.json | 22 +--- .../test/vpc-ipam.integ.snapshot/tree.json | 80 ------------- 12 files changed, 146 insertions(+), 313 deletions(-) rename packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/{asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle => asset.d47f7e6772bfdf47ecbc070ffe204baf53bacbfbf7814eb407bd8ea108c1c1bb.bundle}/index.js (96%) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 2e3b53fd51c80..2106b1634ed96 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -219,31 +219,74 @@ provider.connections.allowFrom(ec2.Peer.ipv4('1.2.3.4/8'), ec2.Port.tcp(80)); ### Ip Address Management - IPAM -To facilitate options for flexibility in the allocation and use of IP space within Vpc and Subnet including strategy and implementation for the allocation, Vpc utilizes an IpamProvider. +The VPC spans a supernet IP range, which contains the non-overlapping IPs of it's contained subnets. Possible sources for this IP range are: -By default, the Vpc construct will create and use a StaticIpam for you if you do not pass an `ipamProvider` to Vpc. StaticIpam is an implementation of the Original CDK Vpc and Subnet IP address allocation strategy and implementation. +- You specify an IP range directly by specifying a CIDR +- You allocate an IP range of a given size automatically from AWS IPAM -You must supply at most one of ipamProvider or cidr to Vpc. +If you don't specify anything, by default the Vpc will allocate the 10.0.0.0/16 address range which will be exhaustively spread across all subnets in the subnet configuration. This behavior can be changed (see "Allocating an IP range from AWS IPAM" bellow). -StaticIpam will first try to allocated space from the Vpc Cidr any Subnets that explicitly have a `cidrMask` as part of a SubnetConfiguration, this includes reserved subnets, after this any remaining space is divided between the rest of the required subnets. +Be aware that if you don't specify any ipAddressManager the address space will be fully allocated! If you predict you may need to add more subnet groups later, add them early on and set reserved: true (see the "Advanced Subnet Configuration" section for more information). -When using StaticIpam concrete Cidr values are generated in the synthesized CloudFormation template. +To facilitate options for flexibility in the allocation and use of IP space within Vpc and Subnet including strategy and implementation for the allocation, Vpc utilizes an IpAddressManager. +By default, the Vpc construct will create and use a IpAddressManager.Cidr for you if you do not pass an `IpAddressManager` to Vpc. IpAddressManager.Cidr is an implementation of the Original CDK Vpc and Subnet IP address allocation strategy and implementation. + +You must supply at most one of IpAddressManager or cidr to Vpc. + +#### Specifying an IP range via a CIDR - IpAddressManager.Cidr + +IpAddressManager.Cidr allows you to define a Cidr range directly for your Vpc. + +IpAddressManager.Cidr will first try to allocated space from the Vpc Cidr any Subnets that explicitly have a `cidrMask` as part of a SubnetConfiguration, this includes reserved subnets, after this any remaining space is divided fully between the rest of the required subnets. + +When using IpAddressManager.Cidr concrete Cidr values are generated in the synthesized CloudFormation template. + +Static Ipam can be used by creating a new instance or by using IpAddressManager. + +Using IpAddressManager: +```ts +import { IpAddressManager } from ''@aws-cdk/aws-ec2''; + +new ec2.Vpc(stack, 'TheVPC', { + ipAddressManager: IpAddressManager.cidr('10.0.1.0/20') +}); +``` + +Creating a new Instance of IpAddressManager.Cidr: ```ts new ec2.Vpc(stack, 'TheVPC', { - ipamProvider: new ec2.StaticIpam('10.0.1.0/20') + ipAddressManager: new ec2.Cidr('10.0.1.0/20') }); ``` +#### Allocating an IP range from AWS IPAM - IpAddressManager.AwsIpam + AwsIpam uses Amazon VPC IP Address Manager (IPAM) to allocated the Cidr for the Vpc. For information on Amazon VPC IP Address Manager please see the [official documentation](https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html). AWS Ipam requires a `ipv4IpamPoolId` be set to the Amazon VPC IP Address Manager Pool Id used for the Vpc Cidr allocation, additionally an `ipv4NetmaskLength` must be set, which defines the size of cidr that will be requested from the Pool at deploy time by the CloudFormation engine. Subnets are allocated locally of a size defined by `defaultSubnetIpv4NetmaskLength` in the provider or by using any explicit `cidrMask` from a supplied SubnetConfiguration. The provider AwsIpam dose not attempt to allocated any remaining space in the Vpc's Cidr space. +AwsIpam can be used by creating a new instance or by using IpAddressManager. + +Using IpAddressManager: +```ts +import { IpAddressManager } from ''@aws-cdk/aws-ec2''; + +new ec2.Vpc(stack, 'TheVPC', { + ipAddressManager: IpAddressManager.awsIpam({ + ipv4IpamPoolId: pool.ref, + ipv4NetmaskLength: 18, + defaultSubnetIpv4NetmaskLength: 24 + }) +}); +``` + +Creating a new Instance of AwsIpam: ```ts new ec2.Vpc(stack, 'TheVPC', { - ipamProvider: new ec2.AwsIpam({ + ipAddressManager: new ec2.AwsIpam({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24 @@ -263,9 +306,9 @@ subnet configuration could look like this: ```ts const vpc = new ec2.Vpc(this, 'TheVPC', { - // 'cidr' configures the IP range and size of the entire VPC. + // 'ipAddressManager' configures the IP range and size of the entire VPC. // The IP space will be divided over the configured subnets. - cidr: '10.0.0.0/21', + ipAddressManager: ipAddressManager.cidr('10.0.0.0/21'), // 'maxAzs' configures the maximum number of availability zones to use. // If you want to specify the exact availability zones you want the VPC diff --git a/packages/@aws-cdk/aws-ec2/lib/ipam.ts b/packages/@aws-cdk/aws-ec2/lib/ipam.ts index 1e07d61728ded..f6955da9b0eaa 100644 --- a/packages/@aws-cdk/aws-ec2/lib/ipam.ts +++ b/packages/@aws-cdk/aws-ec2/lib/ipam.ts @@ -6,15 +6,15 @@ import { SubnetConfiguration } from './vpc'; /** * An abstract Provider of Ipam */ -export abstract class IpamProvider { +export abstract class IpAddressManager { /** * Used to provide local Ip Address Management services for your VPC * * VPC Cidr is supplied at creation and subnets are calculated locally * */ - public static staticIpam(cidrBlock: string): IpamProvider { - return new StaticIpam(cidrBlock); + public static cidr(cidrBlock: string): IpAddressManager { + return new Cidr(cidrBlock); } /** @@ -24,7 +24,7 @@ export abstract class IpamProvider { * * @see https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html */ - public static awsIpam(props: AwsIpamProps): IpamProvider { + public static awsIpam(props: AwsIpamProps): IpAddressManager { return new AwsIpam(props); } @@ -46,7 +46,7 @@ export abstract class IpamProvider { /** * Provider of Ipam Implementations */ -export interface IIpamProvider { +export interface IIpAddressManager { /** * Allocates Cidr for Vpc */ @@ -193,7 +193,7 @@ export interface AwsIpamProps { * * ```ts * new ec2.Vpc(stack, 'TheVPC', { - * ipamProvider: new ec2.AwsIpam({ + * ipAddressManager: new ec2.AwsIpam({ * ipv4IpamPoolId: pool.ref, * ipv4NetmaskLength: 18, * defaultSubnetIpv4NetmaskLength: 24 @@ -202,7 +202,7 @@ export interface AwsIpamProps { * ``` * */ -export class AwsIpam implements IIpamProvider { +export class AwsIpam implements IIpAddressManager { constructor(private readonly props: AwsIpamProps) {} /** @@ -258,12 +258,12 @@ export class AwsIpam implements IIpamProvider { * * ```ts * new ec2.Vpc(stack, 'TheVPC', { - * ipamProvider: new ec2.StaticIpam('10.0.1.0/20') + * ipAddressManager: new ec2.IpAddressManager.Cidr('10.0.1.0/20') * }); * ``` * */ -export class StaticIpam implements IIpamProvider { +export class Cidr implements IIpAddressManager { private readonly networkBuilder: NetworkBuilder; constructor(private readonly cidrBlock: string) { @@ -271,7 +271,7 @@ export class StaticIpam implements IIpamProvider { } /** - * Allocates Vpc Cidr. called when creating a Vpc using StaticIpam. + * Allocates Vpc Cidr. called when creating a Vpc using IpAddressManager.Cidr. */ allocateVpcCidr(): VpcIpamOptions { return { diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 74de9db8f67c1..96c80e27acf73 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -10,7 +10,7 @@ import { CfnEIP, CfnInternetGateway, CfnNatGateway, CfnRoute, CfnRouteTable, CfnSubnet, CfnSubnetRouteTableAssociation, CfnVPC, CfnVPCGatewayAttachment, CfnVPNGatewayRoutePropagation, } from './ec2.generated'; -import { AllocatedSubnet, IIpamProvider, RequestedSubnet, StaticIpam } from './ipam'; +import { AllocatedSubnet, IIpAddressManager as IIpAddressManager, RequestedSubnet, Cidr } from './ipam'; import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; import { SubnetFilter } from './subnet'; @@ -818,7 +818,7 @@ export interface VpcProps { * * @default ipam.StaticIpam */ - readonly ipamProvider?: IIpamProvider; + readonly ipAddressManager?: IIpAddressManager; /** * The CIDR range to use for the VPC, e.g. '10.0.0.0/16'. @@ -828,7 +828,7 @@ export interface VpcProps { * * @default Vpc.DEFAULT_CIDR_RANGE * - * @deprecated Use ipamProvider instead + * @deprecated Use IpAddressManager instead */ readonly cidr?: string; @@ -1316,7 +1316,7 @@ export class Vpc extends VpcBase { /** * The IPAM provider */ - private readonly ipamProvider: IIpamProvider; + private readonly ipAddressManager: IIpAddressManager; /** * Subnet configurations for this VPC @@ -1350,18 +1350,18 @@ export class Vpc extends VpcBase { throw new Error('\'cidr\' property must be a concrete CIDR string, got a Token (we need to parse it for automatic subdivision)'); } - if (props.ipamProvider && props.cidr) { - throw new Error('supply at most one of ipamProvider or cidr'); + if (props.ipAddressManager && props.cidr) { + throw new Error('supply at most one of ipAddressManager or cidr'); } - this.ipamProvider = props.ipamProvider ?? new StaticIpam(cidrBlock); + this.ipAddressManager = props.ipAddressManager ?? new Cidr(cidrBlock); this.dnsHostnamesEnabled = props.enableDnsHostnames == null ? true : props.enableDnsHostnames; this.dnsSupportEnabled = props.enableDnsSupport == null ? true : props.enableDnsSupport; const instanceTenancy = props.defaultInstanceTenancy || 'default'; this.internetConnectivityEstablished = this._internetConnectivityEstablished; - const vpcIpamOptions = this.ipamProvider.allocateVpcCidr(); + const vpcIpamOptions = this.ipAddressManager.allocateVpcCidr(); // Define a VPC using the provided CIDR range this.resource = new CfnVPC(this, 'Resource', { @@ -1540,7 +1540,7 @@ export class Vpc extends VpcBase { }, ))); - const { allocatedSubnets } = this.ipamProvider.allocateSubnetsCidr({ + const { allocatedSubnets } = this.ipAddressManager.allocateSubnetsCidr({ vpcCidr: this.vpcCidrBlock, requestedSubnets, }); diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts index d44b266f137aa..d5cc09dfa06f7 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts @@ -5,6 +5,13 @@ import { AwsIpam, CfnIPAM, CfnIPAMPool, CfnVPC, SubnetType, Vpc } from '../lib'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-ec2-ipam-vpc'); +/** + * ### MANUAL CLEAN UP REQUIRED ### + * + * When IPAM is created running this integ-test it is not currently removed after the test run is complete. + * + */ + const ipam = new CfnIPAM(stack, 'IPAM', { operatingRegions: [ { regionName: stack.region }, @@ -29,7 +36,7 @@ const pool = new CfnIPAMPool(stack, 'Pool', { pool.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN); const awsIpamVpc = new Vpc(stack, 'AwsIpamVpc', { - ipamProvider: new AwsIpam({ + ipAddressManager: new AwsIpam({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24, diff --git a/packages/@aws-cdk/aws-ec2/test/ipam.test.ts b/packages/@aws-cdk/aws-ec2/test/ipam.test.ts index 1b75741261632..0ef27a60538f2 100644 --- a/packages/@aws-cdk/aws-ec2/test/ipam.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/ipam.test.ts @@ -1,33 +1,34 @@ + import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; -import { AwsIpam, IpamProvider, StaticIpam, SubnetType, Vpc } from '../lib'; +import { AwsIpam, IpAddressManager, Cidr, SubnetType, Vpc } from '../lib'; -describe('StaticIpam vpc allocation', () => { +describe('Cidr vpc allocation', () => { - test('Default StaticIpam returns the correct vpc cidr', () => { - const ipamProvider = new StaticIpam('10.0.0.0/16'); - expect(ipamProvider.allocateVpcCidr().cidrBlock).toEqual('10.0.0.0/16'); + test('Default Cidr returns the correct vpc cidr', () => { + const ipAddressManager = new Cidr('10.0.0.0/16'); + expect(ipAddressManager.allocateVpcCidr().cidrBlock).toEqual('10.0.0.0/16'); }); - test('Default StaticIpam returns ipv4IpamPoolId as undefined', () => { - const ipamProvider = new StaticIpam('10.0.0.0/16'); - expect(ipamProvider.allocateVpcCidr().ipv4IpamPoolId).toBeUndefined; + test('Default Cidr returns ipv4IpamPoolId as undefined', () => { + const ipAddressManager = new Cidr('10.0.0.0/16'); + expect(ipAddressManager.allocateVpcCidr().ipv4IpamPoolId).toBeUndefined; }); - test('Default StaticIpam returns ipv4NetmaskLength as undefined', () => { - const ipamProvider = new StaticIpam('10.0.0.0/16'); - expect(ipamProvider.allocateVpcCidr().ipv4NetmaskLength).toBeUndefined; + test('Default Cidr returns ipv4NetmaskLength as undefined', () => { + const ipAddressManager = new Cidr('10.0.0.0/16'); + expect(ipAddressManager.allocateVpcCidr().ipv4NetmaskLength).toBeUndefined; }); }); -describe('StaticIpam subnets allocation', () => { +describe('IpAddressManager.Cidr subnets allocation', () => { - const staticIpamProps = '10.0.0.0/16'; + const cidrProps = '10.0.0.0/16'; - test('Default StaticIpam returns the correct subnet allocations, when you do not give a cidr for the subnets', () => { - const ipamProvider = new StaticIpam(staticIpamProps); - expect(ipamProvider.allocateSubnetsCidr({ + test('Default Cidr returns the correct subnet allocations, when you do not give a cidr for the subnets', () => { + const ipAddressManager = new Cidr(cidrProps); + expect(ipAddressManager.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -47,9 +48,9 @@ describe('StaticIpam subnets allocation', () => { }).allocatedSubnets).toEqual([{ cidr: '10.0.0.0/17' }, { cidr: '10.0.128.0/17' }]); }); - test('Default StaticIpam returns the correct subnet allocations, when you provide a cidr for the subnets', () => { - const ipamProvider = new StaticIpam(staticIpamProps); - expect(ipamProvider.allocateSubnetsCidr({ + test('Default Cidr returns the correct subnet allocations, when you provide a cidr for the subnets', () => { + const ipAddressManager = new Cidr(cidrProps); + expect(ipAddressManager.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -71,9 +72,9 @@ describe('StaticIpam subnets allocation', () => { }).allocatedSubnets).toEqual([{ cidr: '10.0.0.0/24' }, { cidr: '10.0.1.0/24' }]); }); - test('Default StaticIpam returns the correct subnet allocations, when you mix provide and non provided cidr for the subnets', () => { - const ipamProvider = new StaticIpam(staticIpamProps); - expect(ipamProvider.allocateSubnetsCidr({ + test('Default Cidr returns the correct subnet allocations, when you mix provided and non provided cidr for the subnets', () => { + const ipAddressManager = new Cidr(cidrProps); + expect(ipAddressManager.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -104,18 +105,18 @@ describe('AwsIpam vpc allocation', () => { }; test('AwsIpam returns cidrBlock as undefined', () => { - const ipamProvider = new AwsIpam(awsIpamProps); - expect(ipamProvider.allocateVpcCidr().cidrBlock).toBeUndefined; + const ipAddressManager = new AwsIpam(awsIpamProps); + expect(ipAddressManager.allocateVpcCidr().cidrBlock).toBeUndefined; }); test('AwsIpam returns the correct vpc ipv4IpamPoolId', () => { - const ipamProvider = new AwsIpam(awsIpamProps); - expect(ipamProvider.allocateVpcCidr().ipv4IpamPoolId).toEqual('ipam-pool-0111222333444'); + const ipAddressManager = new AwsIpam(awsIpamProps); + expect(ipAddressManager.allocateVpcCidr().ipv4IpamPoolId).toEqual('ipam-pool-0111222333444'); }); test('AwsIpam returns the correct vpc ipv4NetmaskLength', () => { - const ipamProvider = new AwsIpam(awsIpamProps); - expect(ipamProvider.allocateVpcCidr().ipv4NetmaskLength).toEqual(22); + const ipAddressManager = new AwsIpam(awsIpamProps); + expect(ipAddressManager.allocateVpcCidr().ipv4NetmaskLength).toEqual(22); }); }); @@ -128,8 +129,8 @@ describe('AwsIpam subnets allocation', () => { }; test('AwsIpam returns subnet allocations as 2x TOKEN, when you do not give a cidr for the subnets', () => { - const ipamProvider = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); - const allocations = ipamProvider.allocateSubnetsCidr({ + const ipAddressManager = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const allocations = ipAddressManager.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -154,8 +155,8 @@ describe('AwsIpam subnets allocation', () => { }); test('AwsIpam returns subnet allocations as 2x TOKEN, when you provide a cidr for the subnets', () => { - const ipamProvider = new AwsIpam(awsIpamProps); - const allocations = ipamProvider.allocateSubnetsCidr({ + const ipAddressManager = new AwsIpam(awsIpamProps); + const allocations = ipAddressManager.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -182,8 +183,8 @@ describe('AwsIpam subnets allocation', () => { }); test('AwsIpam returns subnet allocations as 2x TOKEN, when you mix provide and non provided cidr for the subnets', () => { - const ipamProvider = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); - const allocations = ipamProvider.allocateSubnetsCidr({ + const ipAddressManager = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const allocations = ipAddressManager.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -210,29 +211,29 @@ describe('AwsIpam subnets allocation', () => { }); -describe('StaticIpam Vpc Integration', () => { - test('StaticIpam provides the correct Cidr allocation to the Vpc ', () => { +describe('IpAddressManager.cidr Vpc Integration', () => { + test('IpAddressManager.Cidr provides the correct Cidr allocation to the Vpc ', () => { const stack = new Stack(); - const staticIpamProps = '10.0.0.0/16'; - const ipamProvider = IpamProvider.staticIpam(staticIpamProps); + const cidrProps = '10.0.0.0/16'; + const ipAddressManager = IpAddressManager.cidr(cidrProps); - new Vpc(stack, 'VpcNetwork', { ipamProvider }); + new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager }); Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { - CidrBlock: staticIpamProps, + CidrBlock: cidrProps, }); }); - test('StaticIpam provides the correct Subnet allocation to the Vpc', () => { + test('IpAddressManager.cidr provides the correct Subnet allocation to the Vpc', () => { const stack = new Stack(); - const staticIpamProps = '10.0.0.0/16'; - const ipamProvider = IpamProvider.staticIpam(staticIpamProps); + const cidrProps = '10.0.0.0/16'; + const ipAddressManager = IpAddressManager.cidr(cidrProps); - new Vpc(stack, 'VpcNetwork', { ipamProvider }); + new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager }); const template = Template.fromStack(stack); @@ -262,9 +263,9 @@ describe('AwsIpam Vpc Integration', () => { ipv4NetmaskLength: 22, }; - const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); - expect(() => {new Vpc(stack, 'VpcNetwork', { ipamProvider });}).toThrow(/If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in the provider/);; + expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager });}).toThrow(/If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in the provider/);; }); @@ -278,9 +279,9 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 24, }; - const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); - new Vpc(stack, 'VpcNetwork', { ipamProvider }); + new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager }); Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { Ipv4IpamPoolId: awsIpamProps.ipv4IpamPoolId, @@ -299,9 +300,9 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 24, }; - const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); - new Vpc(stack, 'VpcNetwork', { ipamProvider }); + new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager }); const template = Template.fromStack(stack); @@ -353,9 +354,9 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 17, }; - const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); - expect(() => {new Vpc(stack, 'VpcNetwork', { ipamProvider });}).toThrow('IP space of size /18 not big enough to allocate subnets of sizes /17,/17,/17,/17');; + expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager });}).toThrow('IP space of size /18 not big enough to allocate subnets of sizes /17,/17,/17,/17');; }); @@ -369,10 +370,10 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 17, }; - const ipamProvider = IpamProvider.awsIpam(awsIpamProps); + const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); new Vpc(stack, 'VpcNetwork', { - ipamProvider, + ipAddressManager: ipAddressManager, subnetConfiguration: [{ name: 'public', subnetType: SubnetType.PUBLIC, diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json index b7f477b027c1a..2c3f67423ff8b 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.assets.json @@ -1,20 +1,20 @@ { "version": "21.0.0", "files": { - "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd": { + "d47f7e6772bfdf47ecbc070ffe204baf53bacbfbf7814eb407bd8ea108c1c1bb": { "source": { - "path": "asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle", + "path": "asset.d47f7e6772bfdf47ecbc070ffe204baf53bacbfbf7814eb407bd8ea108c1c1bb.bundle", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.zip", + "objectKey": "d47f7e6772bfdf47ecbc070ffe204baf53bacbfbf7814eb407bd8ea108c1c1bb.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "82bad81cf8eac60f0e51fc423dae939f8eeeeebef3c4bae147061066e0314098": { + "5ee44ec2182f45d2de6a0f0dce2ba54c61792d88196caa30d00380d2a5bb40c2": { "source": { "path": "VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "82bad81cf8eac60f0e51fc423dae939f8eeeeebef3c4bae147061066e0314098.json", + "objectKey": "5ee44ec2182f45d2de6a0f0dce2ba54c61792d88196caa30d00380d2a5bb40c2.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json index 69202e02f7710..36052e44320fd 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/VpcIpamDefaultTestDeployAssertB1CA1C3A.template.json @@ -20,8 +20,7 @@ ] }, "flattenResponse": "false", - "salt": "1665391872401", - "installLatestAwsSdk": false + "salt": "1666602022682" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -75,7 +74,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.zip" + "S3Key": "d47f7e6772bfdf47ecbc070ffe204baf53bacbfbf7814eb407bd8ea108c1c1bb.zip" }, "Timeout": 120, "Handler": "index.handler", diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle/index.js b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.d47f7e6772bfdf47ecbc070ffe204baf53bacbfbf7814eb407bd8ea108c1c1bb.bundle/index.js similarity index 96% rename from packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle/index.js rename to packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.d47f7e6772bfdf47ecbc070ffe204baf53bacbfbf7814eb407bd8ea108c1c1bb.bundle/index.js index 184c7f6ac442d..a9e7e7241efc7 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle/index.js +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/asset.d47f7e6772bfdf47ecbc070ffe204baf53bacbfbf7814eb407bd8ea108c1c1bb.bundle/index.js @@ -534,9 +534,6 @@ function decodeCall(call) { } } -// lib/assertions/providers/lambda-handler/sdk.ts -var import_child_process = require("child_process"); - // lib/assertions/providers/lambda-handler/utils.ts function decode(object) { return JSON.parse(JSON.stringify(object), (_k, v) => { @@ -566,24 +563,9 @@ function flatten(object) { }(object) ); } -function installLatestSdk() { - console.log("Installing latest AWS SDK v2"); - (0, import_child_process.execSync)("HOME=/tmp npm install aws-sdk@2 --production --no-package-lock --no-save --prefix /tmp"); -} var AwsApiCallHandler = class extends CustomResourceHandler { async processEvent(request2) { - let AWS; - if (request2.installLatestAwsSdk === "true") { - try { - installLatestSdk(); - AWS = require("/tmp/node_modules/aws-sdk"); - } catch (e) { - console.log(`Failed to install latest AWS SDK v2: ${e}`); - AWS = require("aws-sdk"); - } - } else { - AWS = require("aws-sdk"); - } + const AWS = require("aws-sdk"); console.log(`AWS SDK VERSION: ${AWS.VERSION}`); if (!Object.prototype.hasOwnProperty.call(AWS, request2.service)) { throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS.VERSION}.`); diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.assets.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.assets.json index e0c7241341957..bec195ba38184 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.assets.json +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.assets.json @@ -1,20 +1,7 @@ { "version": "21.0.0", "files": { - "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd": { - "source": { - "path": "asset.a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.bundle", - "packaging": "zip" - }, - "destinations": { - "current_account-current_region": { - "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.zip", - "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" - } - } - }, - "d1725d3e6f9001532273823c6744d8c471e52954ff414ab9e83d5979a47f61a4": { + "5b3a6377cf636bdf8b57c28c24c57742dfd668f4536432348222f40b5ce1a63d": { "source": { "path": "aws-cdk-ec2-ipam-vpc.template.json", "packaging": "file" @@ -22,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "d1725d3e6f9001532273823c6744d8c471e52954ff414ab9e83d5979a47f61a4.json", + "objectKey": "5b3a6377cf636bdf8b57c28c24c57742dfd668f4536432348222f40b5ce1a63d.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.template.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.template.json index cecf8d15b2b0d..82a71e9a08722 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.template.json +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/aws-cdk-ec2-ipam-vpc.template.json @@ -209,94 +209,6 @@ "Ref": "AwsIpamVpcprivateSubnet2Subnet577660DE" } } - }, - "cleanUpIpam": { - "Type": "Custom::DeployAssert@SdkCallEC2deleteIpam", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", - "Arn" - ] - }, - "service": "EC2", - "api": "deleteIpam", - "parameters": { - "IpamId": { - "Fn::GetAtt": [ - "IPAM", - "IpamId" - ] - }, - "Cascade": "TRUE:BOOLEAN" - }, - "flattenResponse": "false", - "salt": "1665391872399", - "installLatestAwsSdk": true - }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, - "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - } - ] - }, - "ManagedPolicyArns": [ - { - "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - } - ], - "Policies": [ - { - "PolicyName": "Inline", - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Action": [ - "ec2:DeleteIpam" - ], - "Effect": "Allow", - "Resource": [ - "*" - ] - } - ] - } - } - ] - } - }, - "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Runtime": "nodejs14.x", - "Code": { - "S3Bucket": { - "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" - }, - "S3Key": "a5e47e41a5a1802f0a9a6c50ddee0834c5823b35e240ee1a8830e87aebef46cd.zip" - }, - "Timeout": 120, - "Handler": "index.handler", - "Role": { - "Fn::GetAtt": [ - "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", - "Arn" - ] - } - } } }, "Outputs": { diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/manifest.json index 3ae93500bd78f..98824f54ae317 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/manifest.json @@ -23,7 +23,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/d1725d3e6f9001532273823c6744d8c471e52954ff414ab9e83d5979a47f61a4.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5b3a6377cf636bdf8b57c28c24c57742dfd668f4536432348222f40b5ce1a63d.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -93,24 +93,6 @@ "data": "AwsIpamVpcprivateSubnet2RouteTableAssociation52A3C85A" } ], - "/aws-cdk-ec2-ipam-vpc/cleanUpIpam/Default/Default": [ - { - "type": "aws:cdk:logicalId", - "data": "cleanUpIpam" - } - ], - "/aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ - { - "type": "aws:cdk:logicalId", - "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" - } - ], - "/aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ - { - "type": "aws:cdk:logicalId", - "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" - } - ], "/aws-cdk-ec2-ipam-vpc/Exports/Output{\"Fn::GetAtt\":[\"AwsIpamVpcD3A1DAEE\",\"VpcId\"]}": [ { "type": "aws:cdk:logicalId", @@ -148,7 +130,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/82bad81cf8eac60f0e51fc423dae939f8eeeeebef3c4bae147061066e0314098.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5ee44ec2182f45d2de6a0f0dce2ba54c61792d88196caa30d00380d2a5bb40c2.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/tree.json b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/tree.json index 5a6d5ceca4b59..a2e180fba34fa 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/tree.json +++ b/packages/@aws-cdk/aws-ec2/test/vpc-ipam.integ.snapshot/tree.json @@ -340,86 +340,6 @@ "version": "0.0.0" } }, - "cleanUpIpam": { - "id": "cleanUpIpam", - "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam", - "children": { - "SdkProvider": { - "id": "SdkProvider", - "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam/SdkProvider", - "children": { - "AssertionsProvider": { - "id": "AssertionsProvider", - "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam/SdkProvider/AssertionsProvider", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.123" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/integ-tests.AssertionsProvider", - "version": "0.0.0" - } - }, - "Default": { - "id": "Default", - "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam/Default", - "children": { - "Default": { - "id": "Default", - "path": "aws-cdk-ec2-ipam-vpc/cleanUpIpam/Default/Default", - "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/core.CustomResource", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/integ-tests.AwsApiCall", - "version": "0.0.0" - } - }, - "SingletonFunction1488541a7b23466481b69b4408076b81": { - "id": "SingletonFunction1488541a7b23466481b69b4408076b81", - "path": "aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81", - "children": { - "Staging": { - "id": "Staging", - "path": "aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", - "constructInfo": { - "fqn": "@aws-cdk/core.AssetStaging", - "version": "0.0.0" - } - }, - "Role": { - "id": "Role", - "path": "aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Role", - "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", - "version": "0.0.0" - } - }, - "Handler": { - "id": "Handler", - "path": "aws-cdk-ec2-ipam-vpc/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", - "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.123" - } - }, "Exports": { "id": "Exports", "path": "aws-cdk-ec2-ipam-vpc/Exports", From 0b6e993075fef41f3fff9820a7631e0699667e49 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 24 Oct 2022 10:23:39 +0100 Subject: [PATCH 05/20] --fix format --- packages/@aws-cdk/aws-ec2/README.md | 8 ++++++-- packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 2106b1634ed96..de0e7f4f1afba 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -221,8 +221,8 @@ provider.connections.allowFrom(ec2.Peer.ipv4('1.2.3.4/8'), ec2.Port.tcp(80)); The VPC spans a supernet IP range, which contains the non-overlapping IPs of it's contained subnets. Possible sources for this IP range are: -- You specify an IP range directly by specifying a CIDR -- You allocate an IP range of a given size automatically from AWS IPAM +* You specify an IP range directly by specifying a CIDR +* You allocate an IP range of a given size automatically from AWS IPAM If you don't specify anything, by default the Vpc will allocate the 10.0.0.0/16 address range which will be exhaustively spread across all subnets in the subnet configuration. This behavior can be changed (see "Allocating an IP range from AWS IPAM" bellow). @@ -245,6 +245,7 @@ When using IpAddressManager.Cidr concrete Cidr values are generated in the synth Static Ipam can be used by creating a new instance or by using IpAddressManager. Using IpAddressManager: + ```ts import { IpAddressManager } from ''@aws-cdk/aws-ec2''; @@ -254,6 +255,7 @@ new ec2.Vpc(stack, 'TheVPC', { ``` Creating a new Instance of IpAddressManager.Cidr: + ```ts new ec2.Vpc(stack, 'TheVPC', { ipAddressManager: new ec2.Cidr('10.0.1.0/20') @@ -271,6 +273,7 @@ Subnets are allocated locally of a size defined by `defaultSubnetIpv4NetmaskLeng AwsIpam can be used by creating a new instance or by using IpAddressManager. Using IpAddressManager: + ```ts import { IpAddressManager } from ''@aws-cdk/aws-ec2''; @@ -284,6 +287,7 @@ new ec2.Vpc(stack, 'TheVPC', { ``` Creating a new Instance of AwsIpam: + ```ts new ec2.Vpc(stack, 'TheVPC', { ipAddressManager: new ec2.AwsIpam({ diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts index d5cc09dfa06f7..548533cfd4a1f 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts @@ -7,9 +7,9 @@ const stack = new cdk.Stack(app, 'aws-cdk-ec2-ipam-vpc'); /** * ### MANUAL CLEAN UP REQUIRED ### - * + * * When IPAM is created running this integ-test it is not currently removed after the test run is complete. - * + * */ const ipam = new CfnIPAM(stack, 'IPAM', { From 96d1fee84b302d80c2b61dd7925c649adc914a56 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 24 Oct 2022 11:12:28 +0100 Subject: [PATCH 06/20] update tests to remove dep prop cidr --- packages/@aws-cdk/aws-ec2/lib/ipam.ts | 7 +++++- packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 29 +++++++++++----------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/ipam.ts b/packages/@aws-cdk/aws-ec2/lib/ipam.ts index f6955da9b0eaa..f306e15e21836 100644 --- a/packages/@aws-cdk/aws-ec2/lib/ipam.ts +++ b/packages/@aws-cdk/aws-ec2/lib/ipam.ts @@ -1,4 +1,4 @@ -import { Fn } from '@aws-cdk/core'; +import { Fn, Token } from '@aws-cdk/core'; import { calculateCidrSplits } from './cidr-splits'; import { NetworkBuilder } from './network-util'; import { SubnetConfiguration } from './vpc'; @@ -267,6 +267,11 @@ export class Cidr implements IIpAddressManager { private readonly networkBuilder: NetworkBuilder; constructor(private readonly cidrBlock: string) { + + 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)'); + } + this.networkBuilder = new NetworkBuilder(this.cidrBlock); } diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 4fd566f7f1e01..934f368e371d6 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -26,6 +26,7 @@ import { SubnetType, TrafficDirection, Vpc, + IpAddressManager, } from '../lib'; describe('vpc', () => { @@ -174,7 +175,7 @@ describe('vpc', () => { test('with all of the properties set, it successfully sets the correct VPC properties', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { - cidr: '192.168.0.0/16', + ipAddressManager: IpAddressManager.cidr('192.168.0.0/16'), enableDnsHostnames: false, enableDnsSupport: false, defaultInstanceTenancy: DefaultInstanceTenancy.DEDICATED, @@ -205,7 +206,7 @@ describe('vpc', () => { const stack = getTestStack(); const vpc = new Vpc(stack, 'TheVPC', { - cidr: '192.168.0.0/16', + ipAddressManager: IpAddressManager.cidr('192.168.0.0/16'), enableDnsHostnames: input.dnsHostnames, enableDnsSupport: input.dnsSupport, defaultInstanceTenancy: DefaultInstanceTenancy.DEDICATED, @@ -362,7 +363,7 @@ describe('vpc', () => { test('with subnets and reserved subnets defined, VPC subnet count should not contain reserved subnets ', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { - cidr: '10.0.0.0/16', + ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), subnetConfiguration: [ { cidrMask: 24, @@ -389,7 +390,7 @@ describe('vpc', () => { test('with reserved subnets, any other subnets should not have cidrBlock from within reserved space', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { - cidr: '10.0.0.0/16', + ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), subnetConfiguration: [ { cidrMask: 24, @@ -435,7 +436,7 @@ describe('vpc', () => { const stack = getTestStack(); const zones = stack.availabilityZones.length; new Vpc(stack, 'TheVPC', { - cidr: '10.0.0.0/21', + ipAddressManager: IpAddressManager.cidr('10.0.0.0/21'), subnetConfiguration: [ { cidrMask: 24, @@ -473,7 +474,7 @@ describe('vpc', () => { test('with custom subnets and natGateways = 2 there should be only two NATGW', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { - cidr: '10.0.0.0/21', + ipAddressManager: IpAddressManager.cidr('10.0.0.0/21'), natGateways: 2, subnetConfiguration: [ { @@ -845,7 +846,7 @@ describe('vpc', () => { test('natGateways = 0 allows RESERVED PRIVATE subnets', () => { const stack = getTestStack(); new Vpc(stack, 'VPC', { - cidr: '10.0.0.0/16', + ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), subnetConfiguration: [ { name: 'ingress', @@ -869,7 +870,7 @@ describe('vpc', () => { test('EIP passed with NAT gateway does not create duplicate EIP', () => { const stack = getTestStack(); new Vpc(stack, 'VPC', { - cidr: '10.0.0.0/16', + ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), subnetConfiguration: [ { cidrMask: 24, @@ -1131,7 +1132,7 @@ describe('vpc', () => { const stack = new Stack(); expect(() => { new Vpc(stack, 'Vpc', { - cidr: Lazy.string({ produce: () => 'abc' }), + ipAddressManager: IpAddressManager.cidr(Lazy.string({ produce: () => 'abc' })), }); }).toThrow(/property must be a concrete CIDR string/); }); @@ -1453,7 +1454,7 @@ describe('vpc', () => { const stack = getTestStack(); // WHEN - const vpc = new Vpc(stack, 'TheVPC', { cidr: '192.168.0.0/16' }); + const vpc = new Vpc(stack, 'TheVPC', { ipAddressManager: IpAddressManager.cidr('192.168.0.0/16') }); new CfnOutput(stack, 'Output', { value: (vpc.publicSubnets[0] as Subnet).subnetNetworkAclAssociationId, }); @@ -1470,7 +1471,7 @@ describe('vpc', () => { test('if ACL is replaced new ACL reference is returned', () => { // GIVEN const stack = getTestStack(); - const vpc = new Vpc(stack, 'TheVPC', { cidr: '192.168.0.0/16' }); + const vpc = new Vpc(stack, 'TheVPC', { ipAddressManager: IpAddressManager.cidr('192.168.0.0/16') }); // WHEN new CfnOutput(stack, 'Output', { @@ -1494,7 +1495,7 @@ describe('vpc', () => { describe('When creating a VPC with a custom CIDR range', () => { test('vpc.vpcCidrBlock is the correct network range', () => { const stack = getTestStack(); - new Vpc(stack, 'TheVPC', { cidr: '192.168.0.0/16' }); + new Vpc(stack, 'TheVPC', { ipAddressManager: IpAddressManager.cidr('192.168.0.0/16') }); Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { CidrBlock: '192.168.0.0/16', }); @@ -1933,7 +1934,7 @@ describe('vpc', () => { // 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', + ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), maxAzs: 3, }); @@ -1964,7 +1965,7 @@ describe('vpc', () => { // 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', + ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), maxAzs: 3, }); From 08155389da64de86d2835c9ecb0e440f3f2886e4 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 24 Oct 2022 11:46:43 +0100 Subject: [PATCH 07/20] update cidr to ipAddressManager in other module tests --- packages/@aws-cdk/aws-ec2/README.md | 4 ++++ packages/@aws-cdk/aws-ec2/lib/vpc.ts | 2 +- .../@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts | 2 +- .../@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index de0e7f4f1afba..09aa25b13e10a 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -257,6 +257,8 @@ new ec2.Vpc(stack, 'TheVPC', { Creating a new Instance of IpAddressManager.Cidr: ```ts +import * as ec2 from '@aws-cdk/aws-ec2'; + new ec2.Vpc(stack, 'TheVPC', { ipAddressManager: new ec2.Cidr('10.0.1.0/20') }); @@ -289,6 +291,8 @@ new ec2.Vpc(stack, 'TheVPC', { Creating a new Instance of AwsIpam: ```ts +import * as ec2 from '@aws-cdk/aws-ec2'; + new ec2.Vpc(stack, 'TheVPC', { ipAddressManager: new ec2.AwsIpam({ ipv4IpamPoolId: pool.ref, diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 96c80e27acf73..bdc60e5affb05 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -1101,7 +1101,7 @@ export interface SubnetConfiguration { * * ```ts * const vpc = new ec2.Vpc(this, 'TheVPC', { - * cidr: "10.0.0.0/16" + * ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), * }) * * // Iterate the private subnets diff --git a/packages/@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts b/packages/@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts index a19e9864b257e..46cc045c29be8 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts @@ -19,7 +19,7 @@ class VpcReservedPrivateSubnetStack extends cdk.Stack { /// !show // Specify no NAT gateways with a reserved private subnet new ec2.Vpc(this, 'VPC', { - cidr: '10.0.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), subnetConfiguration: [ { name: 'ingress', diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts index c3d06a2e302f1..41aa9e99c4182 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts @@ -5,7 +5,7 @@ const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-ec2-vpn'); const vpc = new ec2.Vpc(stack, 'MyVpc', { - cidr: '10.10.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.10.0.0/16'), vpnConnections: { Dynamic: { // Dynamic routing ip: '52.85.255.164', From 45d7cb3b1e539c1396b1e629275c3ba9a4052ecf Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 24 Oct 2022 12:04:14 +0100 Subject: [PATCH 08/20] update cidr to ipAddressManager in other module tests --- packages/@aws-cdk/aws-apprunner/README.md | 2 +- .../aws-apprunner/test/integ.service-vpc-connector.ts | 2 +- packages/@aws-cdk/aws-apprunner/test/service.test.ts | 2 +- .../@aws-cdk/aws-apprunner/test/vpc-connector.test.ts | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/@aws-cdk/aws-apprunner/README.md b/packages/@aws-cdk/aws-apprunner/README.md index 5e1c1c2b7f7e8..f69c23ce63e62 100644 --- a/packages/@aws-cdk/aws-apprunner/README.md +++ b/packages/@aws-cdk/aws-apprunner/README.md @@ -143,7 +143,7 @@ To associate an App Runner service with a custom VPC, define `vpcConnector` for import * as ec2 from '@aws-cdk/aws-ec2'; const vpc = new ec2.Vpc(this, 'Vpc', { - cidr: '10.0.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16') }); const vpcConnector = new apprunner.VpcConnector(this, 'VpcConnector', { diff --git a/packages/@aws-cdk/aws-apprunner/test/integ.service-vpc-connector.ts b/packages/@aws-cdk/aws-apprunner/test/integ.service-vpc-connector.ts index 5a3aa23eb8008..b1ecee1036ef6 100644 --- a/packages/@aws-cdk/aws-apprunner/test/integ.service-vpc-connector.ts +++ b/packages/@aws-cdk/aws-apprunner/test/integ.service-vpc-connector.ts @@ -9,7 +9,7 @@ const stack = new cdk.Stack(app, 'integ-apprunner'); // Scenario 6: Create the service from ECR public with a VPC Connector const vpc = new ec2.Vpc(stack, 'Vpc', { - cidr: '10.0.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), }); const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); diff --git a/packages/@aws-cdk/aws-apprunner/test/service.test.ts b/packages/@aws-cdk/aws-apprunner/test/service.test.ts index 6b1d882bcda27..9108165d7e735 100644 --- a/packages/@aws-cdk/aws-apprunner/test/service.test.ts +++ b/packages/@aws-cdk/aws-apprunner/test/service.test.ts @@ -619,7 +619,7 @@ test('specifying a vpcConnector should assign the service to it and set the egre const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - cidr: '10.0.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), }); const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); diff --git a/packages/@aws-cdk/aws-apprunner/test/vpc-connector.test.ts b/packages/@aws-cdk/aws-apprunner/test/vpc-connector.test.ts index 7eef67f924381..18e6299312be2 100644 --- a/packages/@aws-cdk/aws-apprunner/test/vpc-connector.test.ts +++ b/packages/@aws-cdk/aws-apprunner/test/vpc-connector.test.ts @@ -9,7 +9,7 @@ test('create a vpcConnector with all properties', () => { const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - cidr: '10.0.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), }); const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); @@ -48,7 +48,7 @@ test('create a vpcConnector without a name', () => { const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - cidr: '10.0.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), }); const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); @@ -85,7 +85,7 @@ test('create a vpcConnector without a security group should create one', () => { const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - cidr: '10.0.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), }); // WHEN @@ -120,7 +120,7 @@ test('create a vpcConnector with an empty security group array should create one const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - cidr: '10.0.0.0/16', + ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), }); // WHEN From d7c9ae5a76f3d95a49591228b1238d128fa0d3b8 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 24 Oct 2022 21:12:08 +0100 Subject: [PATCH 09/20] vpc prop to ipAddresses --- packages/@aws-cdk/aws-apprunner/README.md | 2 +- .../test/integ.service-vpc-connector.ts | 2 +- .../aws-apprunner/test/service.test.ts | 2 +- .../aws-apprunner/test/vpc-connector.test.ts | 8 +- packages/@aws-cdk/aws-ec2/README.md | 50 +++++------ packages/@aws-cdk/aws-ec2/lib/ipam.ts | 24 +++--- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 32 +++---- .../test/integ.reserved-private-subnet.ts | 2 +- .../@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts | 2 +- .../test/integ.vpn-pre-shared-key-token.ts | 2 +- packages/@aws-cdk/aws-ec2/test/ipam.test.ts | 86 +++++++++---------- packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 30 +++---- 12 files changed, 121 insertions(+), 121 deletions(-) diff --git a/packages/@aws-cdk/aws-apprunner/README.md b/packages/@aws-cdk/aws-apprunner/README.md index f69c23ce63e62..de5aa782b26df 100644 --- a/packages/@aws-cdk/aws-apprunner/README.md +++ b/packages/@aws-cdk/aws-apprunner/README.md @@ -143,7 +143,7 @@ To associate an App Runner service with a custom VPC, define `vpcConnector` for import * as ec2 from '@aws-cdk/aws-ec2'; const vpc = new ec2.Vpc(this, 'Vpc', { - ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16') + ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16') }); const vpcConnector = new apprunner.VpcConnector(this, 'VpcConnector', { diff --git a/packages/@aws-cdk/aws-apprunner/test/integ.service-vpc-connector.ts b/packages/@aws-cdk/aws-apprunner/test/integ.service-vpc-connector.ts index b1ecee1036ef6..487a1b2569f14 100644 --- a/packages/@aws-cdk/aws-apprunner/test/integ.service-vpc-connector.ts +++ b/packages/@aws-cdk/aws-apprunner/test/integ.service-vpc-connector.ts @@ -9,7 +9,7 @@ const stack = new cdk.Stack(app, 'integ-apprunner'); // Scenario 6: Create the service from ECR public with a VPC Connector const vpc = new ec2.Vpc(stack, 'Vpc', { - ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), }); const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); diff --git a/packages/@aws-cdk/aws-apprunner/test/service.test.ts b/packages/@aws-cdk/aws-apprunner/test/service.test.ts index 9108165d7e735..ed41689c9f255 100644 --- a/packages/@aws-cdk/aws-apprunner/test/service.test.ts +++ b/packages/@aws-cdk/aws-apprunner/test/service.test.ts @@ -619,7 +619,7 @@ test('specifying a vpcConnector should assign the service to it and set the egre const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), }); const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); diff --git a/packages/@aws-cdk/aws-apprunner/test/vpc-connector.test.ts b/packages/@aws-cdk/aws-apprunner/test/vpc-connector.test.ts index 18e6299312be2..71baeac75b692 100644 --- a/packages/@aws-cdk/aws-apprunner/test/vpc-connector.test.ts +++ b/packages/@aws-cdk/aws-apprunner/test/vpc-connector.test.ts @@ -9,7 +9,7 @@ test('create a vpcConnector with all properties', () => { const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), }); const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); @@ -48,7 +48,7 @@ test('create a vpcConnector without a name', () => { const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), }); const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); @@ -85,7 +85,7 @@ test('create a vpcConnector without a security group should create one', () => { const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), }); // WHEN @@ -120,7 +120,7 @@ test('create a vpcConnector with an empty security group array should create one const stack = new cdk.Stack(app, 'demo-stack'); const vpc = new ec2.Vpc(stack, 'Vpc', { - ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), }); // WHEN diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 09aa25b13e10a..52e2094d67061 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -217,7 +217,7 @@ new ec2.Vpc(this, 'TheVPC', { provider.connections.allowFrom(ec2.Peer.ipv4('1.2.3.4/8'), ec2.Port.tcp(80)); ``` -### Ip Address Management - IPAM +### Ip Address Management The VPC spans a supernet IP range, which contains the non-overlapping IPs of it's contained subnets. Possible sources for this IP range are: @@ -226,61 +226,61 @@ The VPC spans a supernet IP range, which contains the non-overlapping IPs of it If you don't specify anything, by default the Vpc will allocate the 10.0.0.0/16 address range which will be exhaustively spread across all subnets in the subnet configuration. This behavior can be changed (see "Allocating an IP range from AWS IPAM" bellow). -Be aware that if you don't specify any ipAddressManager the address space will be fully allocated! If you predict you may need to add more subnet groups later, add them early on and set reserved: true (see the "Advanced Subnet Configuration" section for more information). +Be aware that if you don't specify 'ipAddresses' the address space will be fully allocated! If you predict you may need to add more subnet groups later, add them early on and set reserved: true (see the "Advanced Subnet Configuration" section for more information). -To facilitate options for flexibility in the allocation and use of IP space within Vpc and Subnet including strategy and implementation for the allocation, Vpc utilizes an IpAddressManager. +To facilitate options for flexibility in the allocation and use of IP space within Vpc and Subnet including strategy and implementation for the allocation, Vpc utilizes 'ipAddresses'. -By default, the Vpc construct will create and use a IpAddressManager.Cidr for you if you do not pass an `IpAddressManager` to Vpc. IpAddressManager.Cidr is an implementation of the Original CDK Vpc and Subnet IP address allocation strategy and implementation. +By default, the Vpc construct will create and use a ec2.Cidr for you if you do not set the Vpc ipAddresses property. ec2.Cidr is an implementation of the Original CDK Vpc and Subnet IP address allocation strategy and implementation. -You must supply at most one of IpAddressManager or cidr to Vpc. +You must supply at most one of 'ipAddresses' or 'cidr' to Vpc. -#### Specifying an IP range via a CIDR - IpAddressManager.Cidr +#### Specifying an IP range via a CIDR - IpAddresses.Cidr -IpAddressManager.Cidr allows you to define a Cidr range directly for your Vpc. +ec2.Cidr allows you to define a Cidr range directly for your Vpc. -IpAddressManager.Cidr will first try to allocated space from the Vpc Cidr any Subnets that explicitly have a `cidrMask` as part of a SubnetConfiguration, this includes reserved subnets, after this any remaining space is divided fully between the rest of the required subnets. +ec2.Cidr will first try to allocated space from the Vpc Cidr any Subnets that explicitly have a `cidrMask` as part of a SubnetConfiguration, this includes reserved subnets, after this any remaining space is divided fully between the rest of the required subnets. -When using IpAddressManager.Cidr concrete Cidr values are generated in the synthesized CloudFormation template. +When using ec2.Cidr concrete Cidr values are generated in the synthesized CloudFormation template. -Static Ipam can be used by creating a new instance or by using IpAddressManager. +ec2.Cidr can be used by creating a new instance or by using 'IpAddresses'. -Using IpAddressManager: +Using IpAddresses: ```ts -import { IpAddressManager } from ''@aws-cdk/aws-ec2''; +import { IpAddresses } from ''@aws-cdk/aws-ec2''; new ec2.Vpc(stack, 'TheVPC', { - ipAddressManager: IpAddressManager.cidr('10.0.1.0/20') + ipAddresses: IpAddresses.cidr('10.0.1.0/20') }); ``` -Creating a new Instance of IpAddressManager.Cidr: +Creating a new Instance of Cidr: ```ts import * as ec2 from '@aws-cdk/aws-ec2'; new ec2.Vpc(stack, 'TheVPC', { - ipAddressManager: new ec2.Cidr('10.0.1.0/20') + ipAddresses: new ec2.Cidr('10.0.1.0/20') }); ``` -#### Allocating an IP range from AWS IPAM - IpAddressManager.AwsIpam +#### Allocating an IP range from AWS IPAM - IpAddresses.AwsIpam AwsIpam uses Amazon VPC IP Address Manager (IPAM) to allocated the Cidr for the Vpc. For information on Amazon VPC IP Address Manager please see the [official documentation](https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html). AWS Ipam requires a `ipv4IpamPoolId` be set to the Amazon VPC IP Address Manager Pool Id used for the Vpc Cidr allocation, additionally an `ipv4NetmaskLength` must be set, which defines the size of cidr that will be requested from the Pool at deploy time by the CloudFormation engine. -Subnets are allocated locally of a size defined by `defaultSubnetIpv4NetmaskLength` in the provider or by using any explicit `cidrMask` from a supplied SubnetConfiguration. The provider AwsIpam dose not attempt to allocated any remaining space in the Vpc's Cidr space. +Subnets are allocated locally of a size defined by `defaultSubnetIpv4NetmaskLength` property or by using any explicit `cidrMask` from a supplied SubnetConfiguration. The provider AwsIpam dose not attempt to allocated any remaining space in the Vpc's Cidr space. -AwsIpam can be used by creating a new instance or by using IpAddressManager. +AwsIpam can be used by creating a new instance or by using 'IpAddresses'. -Using IpAddressManager: +Using IpAddresses: ```ts -import { IpAddressManager } from ''@aws-cdk/aws-ec2''; +import { IpAddresses } from ''@aws-cdk/aws-ec2''; new ec2.Vpc(stack, 'TheVPC', { - ipAddressManager: IpAddressManager.awsIpam({ + ipAddresses: IpAddresses.awsIpam({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24 @@ -294,7 +294,7 @@ Creating a new Instance of AwsIpam: import * as ec2 from '@aws-cdk/aws-ec2'; new ec2.Vpc(stack, 'TheVPC', { - ipAddressManager: new ec2.AwsIpam({ + ipAddresses: new ec2.AwsIpam({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24 @@ -314,9 +314,9 @@ subnet configuration could look like this: ```ts const vpc = new ec2.Vpc(this, 'TheVPC', { - // 'ipAddressManager' configures the IP range and size of the entire VPC. - // The IP space will be divided over the configured subnets. - ipAddressManager: ipAddressManager.cidr('10.0.0.0/21'), + // 'IpAddresses' configures the IP range and size of the entire VPC. + // The IP space will be divided based on configuration for the subnets. + ipAddresses: IpAddresses.cidr('10.0.0.0/21'), // 'maxAzs' configures the maximum number of availability zones to use. // If you want to specify the exact availability zones you want the VPC diff --git a/packages/@aws-cdk/aws-ec2/lib/ipam.ts b/packages/@aws-cdk/aws-ec2/lib/ipam.ts index f306e15e21836..1d7edbe0a6b28 100644 --- a/packages/@aws-cdk/aws-ec2/lib/ipam.ts +++ b/packages/@aws-cdk/aws-ec2/lib/ipam.ts @@ -4,16 +4,16 @@ import { NetworkBuilder } from './network-util'; import { SubnetConfiguration } from './vpc'; /** - * An abstract Provider of Ipam + * An abstract Provider of IpAddresses */ -export abstract class IpAddressManager { +export abstract class IpAddresses { /** * Used to provide local Ip Address Management services for your VPC * * VPC Cidr is supplied at creation and subnets are calculated locally * */ - public static cidr(cidrBlock: string): IpAddressManager { + public static cidr(cidrBlock: string): IpAddresses { return new Cidr(cidrBlock); } @@ -24,7 +24,7 @@ export abstract class IpAddressManager { * * @see https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html */ - public static awsIpam(props: AwsIpamProps): IpAddressManager { + public static awsIpam(props: AwsIpamProps): IpAddresses { return new AwsIpam(props); } @@ -44,9 +44,9 @@ export abstract class IpAddressManager { } /** - * Provider of Ipam Implementations + * Implementations for ip address management */ -export interface IIpAddressManager { +export interface IIpAddresses { /** * Allocates Cidr for Vpc */ @@ -193,7 +193,7 @@ export interface AwsIpamProps { * * ```ts * new ec2.Vpc(stack, 'TheVPC', { - * ipAddressManager: new ec2.AwsIpam({ + * ipAddresses: new ec2.AwsIpam({ * ipv4IpamPoolId: pool.ref, * ipv4NetmaskLength: 18, * defaultSubnetIpv4NetmaskLength: 24 @@ -202,7 +202,7 @@ export interface AwsIpamProps { * ``` * */ -export class AwsIpam implements IIpAddressManager { +export class AwsIpam implements IIpAddresses { constructor(private readonly props: AwsIpamProps) {} /** @@ -223,7 +223,7 @@ export class AwsIpam implements IIpAddressManager { const cidrSplit = calculateCidrSplits(this.props.ipv4NetmaskLength, input.requestedSubnets.map((mask => { if ((mask.configuration.cidrMask === undefined) && (this.props.defaultSubnetIpv4NetmaskLength=== undefined) ) { - throw new Error('If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in the provider'); + throw new Error('If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in AwsIpam Options'); } const cidrMask = mask.configuration.cidrMask ?? this.props.defaultSubnetIpv4NetmaskLength; @@ -258,12 +258,12 @@ export class AwsIpam implements IIpAddressManager { * * ```ts * new ec2.Vpc(stack, 'TheVPC', { - * ipAddressManager: new ec2.IpAddressManager.Cidr('10.0.1.0/20') + * ipAddresses: new ec2.IpAddresses.Cidr('10.0.1.0/20') * }); * ``` * */ -export class Cidr implements IIpAddressManager { +export class Cidr implements IIpAddresses { private readonly networkBuilder: NetworkBuilder; constructor(private readonly cidrBlock: string) { @@ -276,7 +276,7 @@ export class Cidr implements IIpAddressManager { } /** - * Allocates Vpc Cidr. called when creating a Vpc using IpAddressManager.Cidr. + * Allocates Vpc Cidr. called when creating a Vpc using IpAddresses.Cidr. */ allocateVpcCidr(): VpcIpamOptions { return { diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index bdc60e5affb05..e2f3119619ce1 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -10,7 +10,7 @@ import { CfnEIP, CfnInternetGateway, CfnNatGateway, CfnRoute, CfnRouteTable, CfnSubnet, CfnSubnetRouteTableAssociation, CfnVPC, CfnVPCGatewayAttachment, CfnVPNGatewayRoutePropagation, } from './ec2.generated'; -import { AllocatedSubnet, IIpAddressManager as IIpAddressManager, RequestedSubnet, Cidr } from './ipam'; +import { AllocatedSubnet, IIpAddresses as IIpAddresses, RequestedSubnet, Cidr } from './ipam'; import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; import { SubnetFilter } from './subnet'; @@ -812,13 +812,13 @@ const NAME_TAG: string = 'Name'; export interface VpcProps { /** - * The Ipam Provider to use to allocate IP Space to your VPC. + * The Provider to use to allocate IP Space to your VPC. * * Options include static allocation or from a pool. * - * @default ipam.StaticIpam + * @default ec2.Cidr */ - readonly ipAddressManager?: IIpAddressManager; + readonly ipAddresses?: IIpAddresses; /** * The CIDR range to use for the VPC, e.g. '10.0.0.0/16'. @@ -828,7 +828,7 @@ export interface VpcProps { * * @default Vpc.DEFAULT_CIDR_RANGE * - * @deprecated Use IpAddressManager instead + * @deprecated Use ipAddresses instead */ readonly cidr?: string; @@ -1101,7 +1101,7 @@ export interface SubnetConfiguration { * * ```ts * const vpc = new ec2.Vpc(this, 'TheVPC', { - * ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), + * ipAddresses: IpAddresses.cidr('10.0.0.0/16'), * }) * * // Iterate the private subnets @@ -1314,9 +1314,9 @@ export class Vpc extends VpcBase { private readonly resource: CfnVPC; /** - * The IPAM provider + * The provider of ip addresses */ - private readonly ipAddressManager: IIpAddressManager; + private readonly ipAddresses: IIpAddresses; /** * Subnet configurations for this VPC @@ -1350,24 +1350,24 @@ export class Vpc extends VpcBase { throw new Error('\'cidr\' property must be a concrete CIDR string, got a Token (we need to parse it for automatic subdivision)'); } - if (props.ipAddressManager && props.cidr) { - throw new Error('supply at most one of ipAddressManager or cidr'); + if (props.ipAddresses && props.cidr) { + throw new Error('supply at most one of ipAddresses or cidr'); } - this.ipAddressManager = props.ipAddressManager ?? new Cidr(cidrBlock); + this.ipAddresses = props.ipAddresses ?? new Cidr(cidrBlock); this.dnsHostnamesEnabled = props.enableDnsHostnames == null ? true : props.enableDnsHostnames; this.dnsSupportEnabled = props.enableDnsSupport == null ? true : props.enableDnsSupport; const instanceTenancy = props.defaultInstanceTenancy || 'default'; this.internetConnectivityEstablished = this._internetConnectivityEstablished; - const vpcIpamOptions = this.ipAddressManager.allocateVpcCidr(); + const vpcIpAddressOptions = this.ipAddresses.allocateVpcCidr(); // Define a VPC using the provided CIDR range this.resource = new CfnVPC(this, 'Resource', { - cidrBlock: vpcIpamOptions.cidrBlock, - ipv4IpamPoolId: vpcIpamOptions.ipv4IpamPoolId, - ipv4NetmaskLength: vpcIpamOptions.ipv4NetmaskLength, + cidrBlock: vpcIpAddressOptions.cidrBlock, + ipv4IpamPoolId: vpcIpAddressOptions.ipv4IpamPoolId, + ipv4NetmaskLength: vpcIpAddressOptions.ipv4NetmaskLength, enableDnsHostnames: this.dnsHostnamesEnabled, enableDnsSupport: this.dnsSupportEnabled, instanceTenancy, @@ -1540,7 +1540,7 @@ export class Vpc extends VpcBase { }, ))); - const { allocatedSubnets } = this.ipAddressManager.allocateSubnetsCidr({ + const { allocatedSubnets } = this.ipAddresses.allocateSubnetsCidr({ vpcCidr: this.vpcCidrBlock, requestedSubnets, }); diff --git a/packages/@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts b/packages/@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts index 46cc045c29be8..583983e0aef2a 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.reserved-private-subnet.ts @@ -19,7 +19,7 @@ class VpcReservedPrivateSubnetStack extends cdk.Stack { /// !show // Specify no NAT gateways with a reserved private subnet new ec2.Vpc(this, 'VPC', { - ipAddressManager: ec2.IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'), subnetConfiguration: [ { name: 'ingress', diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts index 548533cfd4a1f..2c8f5742f2cb2 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts @@ -36,7 +36,7 @@ const pool = new CfnIPAMPool(stack, 'Pool', { pool.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN); const awsIpamVpc = new Vpc(stack, 'AwsIpamVpc', { - ipAddressManager: new AwsIpam({ + ipAddresses: new AwsIpam({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24, diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts index 41aa9e99c4182..24d97423bf033 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpn-pre-shared-key-token.ts @@ -5,7 +5,7 @@ const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-ec2-vpn'); const vpc = new ec2.Vpc(stack, 'MyVpc', { - ipAddressManager: ec2.IpAddressManager.cidr('10.10.0.0/16'), + ipAddresses: ec2.IpAddresses.cidr('10.10.0.0/16'), vpnConnections: { Dynamic: { // Dynamic routing ip: '52.85.255.164', diff --git a/packages/@aws-cdk/aws-ec2/test/ipam.test.ts b/packages/@aws-cdk/aws-ec2/test/ipam.test.ts index 0ef27a60538f2..45d80abc20d8a 100644 --- a/packages/@aws-cdk/aws-ec2/test/ipam.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/ipam.test.ts @@ -1,34 +1,34 @@ import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; -import { AwsIpam, IpAddressManager, Cidr, SubnetType, Vpc } from '../lib'; +import { AwsIpam, IpAddresses, Cidr, SubnetType, Vpc } from '../lib'; describe('Cidr vpc allocation', () => { test('Default Cidr returns the correct vpc cidr', () => { - const ipAddressManager = new Cidr('10.0.0.0/16'); - expect(ipAddressManager.allocateVpcCidr().cidrBlock).toEqual('10.0.0.0/16'); + const ipAddresses = new Cidr('10.0.0.0/16'); + expect(ipAddresses.allocateVpcCidr().cidrBlock).toEqual('10.0.0.0/16'); }); test('Default Cidr returns ipv4IpamPoolId as undefined', () => { - const ipAddressManager = new Cidr('10.0.0.0/16'); - expect(ipAddressManager.allocateVpcCidr().ipv4IpamPoolId).toBeUndefined; + const ipAddresses = new Cidr('10.0.0.0/16'); + expect(ipAddresses.allocateVpcCidr().ipv4IpamPoolId).toBeUndefined; }); test('Default Cidr returns ipv4NetmaskLength as undefined', () => { - const ipAddressManager = new Cidr('10.0.0.0/16'); - expect(ipAddressManager.allocateVpcCidr().ipv4NetmaskLength).toBeUndefined; + const ipAddresses = new Cidr('10.0.0.0/16'); + expect(ipAddresses.allocateVpcCidr().ipv4NetmaskLength).toBeUndefined; }); }); -describe('IpAddressManager.Cidr subnets allocation', () => { +describe('IpAddresses.Cidr subnets allocation', () => { const cidrProps = '10.0.0.0/16'; test('Default Cidr returns the correct subnet allocations, when you do not give a cidr for the subnets', () => { - const ipAddressManager = new Cidr(cidrProps); - expect(ipAddressManager.allocateSubnetsCidr({ + const ipAddresses = new Cidr(cidrProps); + expect(ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -49,8 +49,8 @@ describe('IpAddressManager.Cidr subnets allocation', () => { }); test('Default Cidr returns the correct subnet allocations, when you provide a cidr for the subnets', () => { - const ipAddressManager = new Cidr(cidrProps); - expect(ipAddressManager.allocateSubnetsCidr({ + const ipAddresses = new Cidr(cidrProps); + expect(ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -73,8 +73,8 @@ describe('IpAddressManager.Cidr subnets allocation', () => { }); test('Default Cidr returns the correct subnet allocations, when you mix provided and non provided cidr for the subnets', () => { - const ipAddressManager = new Cidr(cidrProps); - expect(ipAddressManager.allocateSubnetsCidr({ + const ipAddresses = new Cidr(cidrProps); + expect(ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -105,18 +105,18 @@ describe('AwsIpam vpc allocation', () => { }; test('AwsIpam returns cidrBlock as undefined', () => { - const ipAddressManager = new AwsIpam(awsIpamProps); - expect(ipAddressManager.allocateVpcCidr().cidrBlock).toBeUndefined; + const ipAddresses = new AwsIpam(awsIpamProps); + expect(ipAddresses.allocateVpcCidr().cidrBlock).toBeUndefined; }); test('AwsIpam returns the correct vpc ipv4IpamPoolId', () => { - const ipAddressManager = new AwsIpam(awsIpamProps); - expect(ipAddressManager.allocateVpcCidr().ipv4IpamPoolId).toEqual('ipam-pool-0111222333444'); + const ipAddresses = new AwsIpam(awsIpamProps); + expect(ipAddresses.allocateVpcCidr().ipv4IpamPoolId).toEqual('ipam-pool-0111222333444'); }); test('AwsIpam returns the correct vpc ipv4NetmaskLength', () => { - const ipAddressManager = new AwsIpam(awsIpamProps); - expect(ipAddressManager.allocateVpcCidr().ipv4NetmaskLength).toEqual(22); + const ipAddresses = new AwsIpam(awsIpamProps); + expect(ipAddresses.allocateVpcCidr().ipv4NetmaskLength).toEqual(22); }); }); @@ -129,8 +129,8 @@ describe('AwsIpam subnets allocation', () => { }; test('AwsIpam returns subnet allocations as 2x TOKEN, when you do not give a cidr for the subnets', () => { - const ipAddressManager = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); - const allocations = ipAddressManager.allocateSubnetsCidr({ + const ipAddresses = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -155,8 +155,8 @@ describe('AwsIpam subnets allocation', () => { }); test('AwsIpam returns subnet allocations as 2x TOKEN, when you provide a cidr for the subnets', () => { - const ipAddressManager = new AwsIpam(awsIpamProps); - const allocations = ipAddressManager.allocateSubnetsCidr({ + const ipAddresses = new AwsIpam(awsIpamProps); + const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -183,8 +183,8 @@ describe('AwsIpam subnets allocation', () => { }); test('AwsIpam returns subnet allocations as 2x TOKEN, when you mix provide and non provided cidr for the subnets', () => { - const ipAddressManager = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); - const allocations = ipAddressManager.allocateSubnetsCidr({ + const ipAddresses = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', configuration: { @@ -211,29 +211,29 @@ describe('AwsIpam subnets allocation', () => { }); -describe('IpAddressManager.cidr Vpc Integration', () => { - test('IpAddressManager.Cidr provides the correct Cidr allocation to the Vpc ', () => { +describe('IpAddresses.cidr Vpc Integration', () => { + test('IpAddresses.cidr provides the correct Cidr allocation to the Vpc ', () => { const stack = new Stack(); const cidrProps = '10.0.0.0/16'; - const ipAddressManager = IpAddressManager.cidr(cidrProps); + const ipAddresses = IpAddresses.cidr(cidrProps); - new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager }); + new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses }); Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { CidrBlock: cidrProps, }); }); - test('IpAddressManager.cidr provides the correct Subnet allocation to the Vpc', () => { + test('IpAddresses.cidr provides the correct Subnet allocation to the Vpc', () => { const stack = new Stack(); const cidrProps = '10.0.0.0/16'; - const ipAddressManager = IpAddressManager.cidr(cidrProps); + const ipAddresses = IpAddresses.cidr(cidrProps); - new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager }); + new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses }); const template = Template.fromStack(stack); @@ -263,9 +263,9 @@ describe('AwsIpam Vpc Integration', () => { ipv4NetmaskLength: 22, }; - const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); - expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager });}).toThrow(/If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in the provider/);; + expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses });}).toThrow(/If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in awsIpam/);; }); @@ -279,9 +279,9 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 24, }; - const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); - new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager }); + new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses }); Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { Ipv4IpamPoolId: awsIpamProps.ipv4IpamPoolId, @@ -300,9 +300,9 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 24, }; - const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); - new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager }); + new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses }); const template = Template.fromStack(stack); @@ -354,9 +354,9 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 17, }; - const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); - expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddressManager: ipAddressManager });}).toThrow('IP space of size /18 not big enough to allocate subnets of sizes /17,/17,/17,/17');; + expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses });}).toThrow('IP space of size /18 not big enough to allocate subnets of sizes /17,/17,/17,/17');; }); @@ -370,10 +370,10 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 17, }; - const ipAddressManager = IpAddressManager.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); new Vpc(stack, 'VpcNetwork', { - ipAddressManager: ipAddressManager, + ipAddresses: ipAddresses, subnetConfiguration: [{ name: 'public', subnetType: SubnetType.PUBLIC, diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 934f368e371d6..e350b1a45b0c8 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -26,7 +26,7 @@ import { SubnetType, TrafficDirection, Vpc, - IpAddressManager, + IpAddresses, } from '../lib'; describe('vpc', () => { @@ -175,7 +175,7 @@ describe('vpc', () => { test('with all of the properties set, it successfully sets the correct VPC properties', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { - ipAddressManager: IpAddressManager.cidr('192.168.0.0/16'), + ipAddresses: IpAddresses.cidr('192.168.0.0/16'), enableDnsHostnames: false, enableDnsSupport: false, defaultInstanceTenancy: DefaultInstanceTenancy.DEDICATED, @@ -206,7 +206,7 @@ describe('vpc', () => { const stack = getTestStack(); const vpc = new Vpc(stack, 'TheVPC', { - ipAddressManager: IpAddressManager.cidr('192.168.0.0/16'), + ipAddresses: IpAddresses.cidr('192.168.0.0/16'), enableDnsHostnames: input.dnsHostnames, enableDnsSupport: input.dnsSupport, defaultInstanceTenancy: DefaultInstanceTenancy.DEDICATED, @@ -363,7 +363,7 @@ describe('vpc', () => { test('with subnets and reserved subnets defined, VPC subnet count should not contain reserved subnets ', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { - ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: IpAddresses.cidr('10.0.0.0/16'), subnetConfiguration: [ { cidrMask: 24, @@ -390,7 +390,7 @@ describe('vpc', () => { test('with reserved subnets, any other subnets should not have cidrBlock from within reserved space', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { - ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: IpAddresses.cidr('10.0.0.0/16'), subnetConfiguration: [ { cidrMask: 24, @@ -436,7 +436,7 @@ describe('vpc', () => { const stack = getTestStack(); const zones = stack.availabilityZones.length; new Vpc(stack, 'TheVPC', { - ipAddressManager: IpAddressManager.cidr('10.0.0.0/21'), + ipAddresses: IpAddresses.cidr('10.0.0.0/21'), subnetConfiguration: [ { cidrMask: 24, @@ -474,7 +474,7 @@ describe('vpc', () => { test('with custom subnets and natGateways = 2 there should be only two NATGW', () => { const stack = getTestStack(); new Vpc(stack, 'TheVPC', { - ipAddressManager: IpAddressManager.cidr('10.0.0.0/21'), + ipAddresses: IpAddresses.cidr('10.0.0.0/21'), natGateways: 2, subnetConfiguration: [ { @@ -846,7 +846,7 @@ describe('vpc', () => { test('natGateways = 0 allows RESERVED PRIVATE subnets', () => { const stack = getTestStack(); new Vpc(stack, 'VPC', { - ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: IpAddresses.cidr('10.0.0.0/16'), subnetConfiguration: [ { name: 'ingress', @@ -870,7 +870,7 @@ describe('vpc', () => { test('EIP passed with NAT gateway does not create duplicate EIP', () => { const stack = getTestStack(); new Vpc(stack, 'VPC', { - ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: IpAddresses.cidr('10.0.0.0/16'), subnetConfiguration: [ { cidrMask: 24, @@ -1132,7 +1132,7 @@ describe('vpc', () => { const stack = new Stack(); expect(() => { new Vpc(stack, 'Vpc', { - ipAddressManager: IpAddressManager.cidr(Lazy.string({ produce: () => 'abc' })), + ipAddresses: IpAddresses.cidr(Lazy.string({ produce: () => 'abc' })), }); }).toThrow(/property must be a concrete CIDR string/); }); @@ -1454,7 +1454,7 @@ describe('vpc', () => { const stack = getTestStack(); // WHEN - const vpc = new Vpc(stack, 'TheVPC', { ipAddressManager: IpAddressManager.cidr('192.168.0.0/16') }); + const vpc = new Vpc(stack, 'TheVPC', { ipAddresses: IpAddresses.cidr('192.168.0.0/16') }); new CfnOutput(stack, 'Output', { value: (vpc.publicSubnets[0] as Subnet).subnetNetworkAclAssociationId, }); @@ -1471,7 +1471,7 @@ describe('vpc', () => { test('if ACL is replaced new ACL reference is returned', () => { // GIVEN const stack = getTestStack(); - const vpc = new Vpc(stack, 'TheVPC', { ipAddressManager: IpAddressManager.cidr('192.168.0.0/16') }); + const vpc = new Vpc(stack, 'TheVPC', { ipAddresses: IpAddresses.cidr('192.168.0.0/16') }); // WHEN new CfnOutput(stack, 'Output', { @@ -1495,7 +1495,7 @@ describe('vpc', () => { describe('When creating a VPC with a custom CIDR range', () => { test('vpc.vpcCidrBlock is the correct network range', () => { const stack = getTestStack(); - new Vpc(stack, 'TheVPC', { ipAddressManager: IpAddressManager.cidr('192.168.0.0/16') }); + new Vpc(stack, 'TheVPC', { ipAddresses: IpAddresses.cidr('192.168.0.0/16') }); Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPC', { CidrBlock: '192.168.0.0/16', }); @@ -1934,7 +1934,7 @@ describe('vpc', () => { // IP space is split into 6 pieces, one public/one private per AZ const vpc = new Vpc(stack, 'VPC', { - ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: IpAddresses.cidr('10.0.0.0/16'), maxAzs: 3, }); @@ -1965,7 +1965,7 @@ describe('vpc', () => { // IP space is split into 6 pieces, one public/one private per AZ const vpc = new Vpc(stack, 'VPC', { - ipAddressManager: IpAddressManager.cidr('10.0.0.0/16'), + ipAddresses: IpAddresses.cidr('10.0.0.0/16'), maxAzs: 3, }); From 454b449a9f37e8cb1bd25848966034fb2861c63c Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 24 Oct 2022 21:27:38 +0100 Subject: [PATCH 10/20] rename ipam file to ip-addresses --- packages/@aws-cdk/aws-ec2/lib/index.ts | 2 +- packages/@aws-cdk/aws-ec2/lib/{ipam.ts => ip-addresses.ts} | 0 packages/@aws-cdk/aws-ec2/lib/vpc.ts | 2 +- .../aws-ec2/test/{ipam.test.ts => ip-addresses.test.ts} | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename packages/@aws-cdk/aws-ec2/lib/{ipam.ts => ip-addresses.ts} (100%) rename packages/@aws-cdk/aws-ec2/test/{ipam.test.ts => ip-addresses.test.ts} (100%) diff --git a/packages/@aws-cdk/aws-ec2/lib/index.ts b/packages/@aws-cdk/aws-ec2/lib/index.ts index 4e65cd23c8054..ce50e5dff927e 100644 --- a/packages/@aws-cdk/aws-ec2/lib/index.ts +++ b/packages/@aws-cdk/aws-ec2/lib/index.ts @@ -27,7 +27,7 @@ export * from './client-vpn-endpoint-types'; export * from './client-vpn-endpoint'; export * from './client-vpn-authorization-rule'; export * from './client-vpn-route'; -export * from './ipam'; +export * from './ip-addresses'; // AWS::EC2 CloudFormation Resources: export * from './ec2.generated'; diff --git a/packages/@aws-cdk/aws-ec2/lib/ipam.ts b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts similarity index 100% rename from packages/@aws-cdk/aws-ec2/lib/ipam.ts rename to packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index e2f3119619ce1..15a85f8b23de2 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -10,7 +10,7 @@ import { CfnEIP, CfnInternetGateway, CfnNatGateway, CfnRoute, CfnRouteTable, CfnSubnet, CfnSubnetRouteTableAssociation, CfnVPC, CfnVPCGatewayAttachment, CfnVPNGatewayRoutePropagation, } from './ec2.generated'; -import { AllocatedSubnet, IIpAddresses as IIpAddresses, RequestedSubnet, Cidr } from './ipam'; +import { AllocatedSubnet, IIpAddresses, RequestedSubnet, Cidr } from './ip-addresses'; import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; import { SubnetFilter } from './subnet'; diff --git a/packages/@aws-cdk/aws-ec2/test/ipam.test.ts b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts similarity index 100% rename from packages/@aws-cdk/aws-ec2/test/ipam.test.ts rename to packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts From af38ad2ee3a363b43a77b484170ade5f0b792a21 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Mon, 24 Oct 2022 21:35:46 +0100 Subject: [PATCH 11/20] update error message test to reflect new message --- packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts index 45d80abc20d8a..9ec69614cc0d6 100644 --- a/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts @@ -265,7 +265,7 @@ describe('AwsIpam Vpc Integration', () => { const ipAddresses = IpAddresses.awsIpam(awsIpamProps); - expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses });}).toThrow(/If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in awsIpam/);; + expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses });}).toThrow(/If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in AwsIpam Options/);; }); From fbee733adbdcd3fd418bbbef2feee2f4f9c11193 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Tue, 25 Oct 2022 20:11:12 +0100 Subject: [PATCH 12/20] no public classes for ipam and cidr --- packages/@aws-cdk/aws-ec2/README.md | 48 ++++--------------- packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts | 6 +-- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 2 +- .../@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts | 4 +- .../aws-ec2/test/ip-addresses.test.ts | 26 +++++----- 5 files changed, 27 insertions(+), 59 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 52e2094d67061..7af54c6dd8bf6 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -230,21 +230,17 @@ Be aware that if you don't specify 'ipAddresses' the address space will be fully To facilitate options for flexibility in the allocation and use of IP space within Vpc and Subnet including strategy and implementation for the allocation, Vpc utilizes 'ipAddresses'. -By default, the Vpc construct will create and use a ec2.Cidr for you if you do not set the Vpc ipAddresses property. ec2.Cidr is an implementation of the Original CDK Vpc and Subnet IP address allocation strategy and implementation. +By default, the Vpc construct will create and use IpAddresses.cidr for you if you do not set the Vpc ipAddresses property. IpAddresses.cidr is an implementation of the Original CDK Vpc and Subnet IP address allocation strategy and implementation. You must supply at most one of 'ipAddresses' or 'cidr' to Vpc. -#### Specifying an IP range via a CIDR - IpAddresses.Cidr +#### Specifying an IP range via a CIDR - IpAddresses.cidr -ec2.Cidr allows you to define a Cidr range directly for your Vpc. +IpAddresses.cidr allows you to define a Cidr range directly for your Vpc. -ec2.Cidr will first try to allocated space from the Vpc Cidr any Subnets that explicitly have a `cidrMask` as part of a SubnetConfiguration, this includes reserved subnets, after this any remaining space is divided fully between the rest of the required subnets. +IpAddresses.cidr will first try to allocated space from the Vpc Cidr any Subnets that explicitly have a `cidrMask` as part of a SubnetConfiguration, this includes reserved subnets, after this any remaining space is divided fully between the rest of the required subnets. -When using ec2.Cidr concrete Cidr values are generated in the synthesized CloudFormation template. - -ec2.Cidr can be used by creating a new instance or by using 'IpAddresses'. - -Using IpAddresses: +When using IpAddresses.cidr concrete Cidr values are generated in the synthesized CloudFormation template. ```ts import { IpAddresses } from ''@aws-cdk/aws-ec2''; @@ -254,28 +250,14 @@ new ec2.Vpc(stack, 'TheVPC', { }); ``` -Creating a new Instance of Cidr: - -```ts -import * as ec2 from '@aws-cdk/aws-ec2'; - -new ec2.Vpc(stack, 'TheVPC', { - ipAddresses: new ec2.Cidr('10.0.1.0/20') -}); -``` - -#### Allocating an IP range from AWS IPAM - IpAddresses.AwsIpam +#### Allocating an IP range from AWS IPAM - IpAddresses.awsIpam -AwsIpam uses Amazon VPC IP Address Manager (IPAM) to allocated the Cidr for the Vpc. For information on Amazon VPC IP Address Manager please see the [official documentation](https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html). +IpAddresses.awsIpam uses Amazon VPC IP Address Manager (IPAM) to allocated the Cidr for the Vpc. For information on Amazon VPC IP Address Manager please see the [official documentation](https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html). AWS Ipam requires a `ipv4IpamPoolId` be set to the Amazon VPC IP Address Manager Pool Id used for the Vpc Cidr allocation, additionally an `ipv4NetmaskLength` must be set, which defines the size of cidr that will be requested from the Pool at deploy time by the CloudFormation engine. Subnets are allocated locally of a size defined by `defaultSubnetIpv4NetmaskLength` property or by using any explicit `cidrMask` from a supplied SubnetConfiguration. The provider AwsIpam dose not attempt to allocated any remaining space in the Vpc's Cidr space. -AwsIpam can be used by creating a new instance or by using 'IpAddresses'. - -Using IpAddresses: - ```ts import { IpAddresses } from ''@aws-cdk/aws-ec2''; @@ -288,21 +270,7 @@ new ec2.Vpc(stack, 'TheVPC', { }); ``` -Creating a new Instance of AwsIpam: - -```ts -import * as ec2 from '@aws-cdk/aws-ec2'; - -new ec2.Vpc(stack, 'TheVPC', { - ipAddresses: new ec2.AwsIpam({ - ipv4IpamPoolId: pool.ref, - ipv4NetmaskLength: 18, - defaultSubnetIpv4NetmaskLength: 24 - }) -}); -``` - -When using AwsIpam the final Cidr allocation for Vpc and Subnets are unknown at synth time. Because of this Subnet Cidr values are synthesized as CloudFormation Intrinsic functions representing their offset within the Vpc Cidr space and not concrete values. +When using IpAddresses.awsIpam the final Cidr allocation for Vpc and Subnets are unknown at synth time. Because of this Subnet Cidr values are synthesized as CloudFormation Intrinsic functions representing their offset within the Vpc Cidr space and not concrete values. ### Advanced Subnet Configuration diff --git a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts index 1d7edbe0a6b28..ae7be0508ede2 100644 --- a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts +++ b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts @@ -193,7 +193,7 @@ export interface AwsIpamProps { * * ```ts * new ec2.Vpc(stack, 'TheVPC', { - * ipAddresses: new ec2.AwsIpam({ + * ipAddresses: new IpAddresses.awsIpam({ * ipv4IpamPoolId: pool.ref, * ipv4NetmaskLength: 18, * defaultSubnetIpv4NetmaskLength: 24 @@ -202,7 +202,7 @@ export interface AwsIpamProps { * ``` * */ -export class AwsIpam implements IIpAddresses { +class AwsIpam implements IIpAddresses { constructor(private readonly props: AwsIpamProps) {} /** @@ -263,7 +263,7 @@ export class AwsIpam implements IIpAddresses { * ``` * */ -export class Cidr implements IIpAddresses { +class Cidr implements IIpAddresses { private readonly networkBuilder: NetworkBuilder; constructor(private readonly cidrBlock: string) { diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 15a85f8b23de2..23b3971c50ca5 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -816,7 +816,7 @@ export interface VpcProps { * * Options include static allocation or from a pool. * - * @default ec2.Cidr + * @default ec2.IpAddresses.cidr */ readonly ipAddresses?: IIpAddresses; diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts index 2c8f5742f2cb2..f032042472b48 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts @@ -1,6 +1,6 @@ import * as cdk from '@aws-cdk/core'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests'; -import { AwsIpam, CfnIPAM, CfnIPAMPool, CfnVPC, SubnetType, Vpc } from '../lib'; +import { IpAddresses, CfnIPAM, CfnIPAMPool, CfnVPC, SubnetType, Vpc } from '../lib'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-ec2-ipam-vpc'); @@ -36,7 +36,7 @@ const pool = new CfnIPAMPool(stack, 'Pool', { pool.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN); const awsIpamVpc = new Vpc(stack, 'AwsIpamVpc', { - ipAddresses: new AwsIpam({ + ipAddresses: IpAddresses.awsIpam({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24, diff --git a/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts index 9ec69614cc0d6..8f2e0e88ecd15 100644 --- a/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts @@ -1,22 +1,22 @@ import { Template } from '@aws-cdk/assertions'; import { Stack } from '@aws-cdk/core'; -import { AwsIpam, IpAddresses, Cidr, SubnetType, Vpc } from '../lib'; +import { IpAddresses, SubnetType, Vpc } from '../lib'; describe('Cidr vpc allocation', () => { test('Default Cidr returns the correct vpc cidr', () => { - const ipAddresses = new Cidr('10.0.0.0/16'); + const ipAddresses = IpAddresses.cidr('10.0.0.0/16'); expect(ipAddresses.allocateVpcCidr().cidrBlock).toEqual('10.0.0.0/16'); }); test('Default Cidr returns ipv4IpamPoolId as undefined', () => { - const ipAddresses = new Cidr('10.0.0.0/16'); + const ipAddresses = IpAddresses.cidr('10.0.0.0/16'); expect(ipAddresses.allocateVpcCidr().ipv4IpamPoolId).toBeUndefined; }); test('Default Cidr returns ipv4NetmaskLength as undefined', () => { - const ipAddresses = new Cidr('10.0.0.0/16'); + const ipAddresses = IpAddresses.cidr('10.0.0.0/16'); expect(ipAddresses.allocateVpcCidr().ipv4NetmaskLength).toBeUndefined; }); @@ -27,7 +27,7 @@ describe('IpAddresses.Cidr subnets allocation', () => { const cidrProps = '10.0.0.0/16'; test('Default Cidr returns the correct subnet allocations, when you do not give a cidr for the subnets', () => { - const ipAddresses = new Cidr(cidrProps); + const ipAddresses = IpAddresses.cidr(cidrProps); expect(ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', @@ -49,7 +49,7 @@ describe('IpAddresses.Cidr subnets allocation', () => { }); test('Default Cidr returns the correct subnet allocations, when you provide a cidr for the subnets', () => { - const ipAddresses = new Cidr(cidrProps); + const ipAddresses = IpAddresses.cidr(cidrProps); expect(ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', @@ -73,7 +73,7 @@ describe('IpAddresses.Cidr subnets allocation', () => { }); test('Default Cidr returns the correct subnet allocations, when you mix provided and non provided cidr for the subnets', () => { - const ipAddresses = new Cidr(cidrProps); + const ipAddresses = IpAddresses.cidr(cidrProps); expect(ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', @@ -105,17 +105,17 @@ describe('AwsIpam vpc allocation', () => { }; test('AwsIpam returns cidrBlock as undefined', () => { - const ipAddresses = new AwsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); expect(ipAddresses.allocateVpcCidr().cidrBlock).toBeUndefined; }); test('AwsIpam returns the correct vpc ipv4IpamPoolId', () => { - const ipAddresses = new AwsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); expect(ipAddresses.allocateVpcCidr().ipv4IpamPoolId).toEqual('ipam-pool-0111222333444'); }); test('AwsIpam returns the correct vpc ipv4NetmaskLength', () => { - const ipAddresses = new AwsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); expect(ipAddresses.allocateVpcCidr().ipv4NetmaskLength).toEqual(22); }); @@ -129,7 +129,7 @@ describe('AwsIpam subnets allocation', () => { }; test('AwsIpam returns subnet allocations as 2x TOKEN, when you do not give a cidr for the subnets', () => { - const ipAddresses = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const ipAddresses = IpAddresses.awsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', @@ -155,7 +155,7 @@ describe('AwsIpam subnets allocation', () => { }); test('AwsIpam returns subnet allocations as 2x TOKEN, when you provide a cidr for the subnets', () => { - const ipAddresses = new AwsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpam(awsIpamProps); const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', @@ -183,7 +183,7 @@ describe('AwsIpam subnets allocation', () => { }); test('AwsIpam returns subnet allocations as 2x TOKEN, when you mix provide and non provided cidr for the subnets', () => { - const ipAddresses = new AwsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const ipAddresses = IpAddresses.awsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', From 0e83d5b0a19ff63f1263d97f361acf6a0c70849c Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Tue, 25 Oct 2022 20:46:36 +0100 Subject: [PATCH 13/20] pushing From 2a929d7ae9e5ccad93132ea9b461dd6f71b10dd4 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Tue, 25 Oct 2022 21:17:43 +0100 Subject: [PATCH 14/20] internal for cidr and ipam --- packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts index ae7be0508ede2..2d5b8aa609d2d 100644 --- a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts +++ b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts @@ -200,7 +200,8 @@ export interface AwsIpamProps { * }) * }); * ``` - * + * + *@internal */ class AwsIpam implements IIpAddresses { constructor(private readonly props: AwsIpamProps) {} @@ -261,7 +262,8 @@ class AwsIpam implements IIpAddresses { * ipAddresses: new ec2.IpAddresses.Cidr('10.0.1.0/20') * }); * ``` - * + * + *@internal */ class Cidr implements IIpAddresses { private readonly networkBuilder: NetworkBuilder; From c01d5bfcd3c0152d7c12b1d1ebc32090bc72792c Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Tue, 25 Oct 2022 21:23:50 +0100 Subject: [PATCH 15/20] fix cidr inport in vpc --- packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts | 10 ++++------ packages/@aws-cdk/aws-ec2/lib/vpc.ts | 4 ++-- packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts index 2d5b8aa609d2d..50040cb3f41c9 100644 --- a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts +++ b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts @@ -200,8 +200,7 @@ export interface AwsIpamProps { * }) * }); * ``` - * - *@internal + * */ class AwsIpam implements IIpAddresses { constructor(private readonly props: AwsIpamProps) {} @@ -259,11 +258,10 @@ class AwsIpam implements IIpAddresses { * * ```ts * new ec2.Vpc(stack, 'TheVPC', { - * ipAddresses: new ec2.IpAddresses.Cidr('10.0.1.0/20') + * ipAddresses: new ec2.IpAddresses.cidr('10.0.1.0/20') * }); * ``` - * - *@internal + * */ class Cidr implements IIpAddresses { private readonly networkBuilder: NetworkBuilder; @@ -278,7 +276,7 @@ class Cidr implements IIpAddresses { } /** - * Allocates Vpc Cidr. called when creating a Vpc using IpAddresses.Cidr. + * Allocates Vpc Cidr. called when creating a Vpc using IpAddresses.cidr. */ allocateVpcCidr(): VpcIpamOptions { return { diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 23b3971c50ca5..719c1f9df4bdf 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -10,7 +10,7 @@ import { CfnEIP, CfnInternetGateway, CfnNatGateway, CfnRoute, CfnRouteTable, CfnSubnet, CfnSubnetRouteTableAssociation, CfnVPC, CfnVPCGatewayAttachment, CfnVPNGatewayRoutePropagation, } from './ec2.generated'; -import { AllocatedSubnet, IIpAddresses, RequestedSubnet, Cidr } from './ip-addresses'; +import { AllocatedSubnet, IIpAddresses, RequestedSubnet, IpAddresses } from './ip-addresses'; import { NatProvider } from './nat'; import { INetworkAcl, NetworkAcl, SubnetNetworkAclAssociation } from './network-acl'; import { SubnetFilter } from './subnet'; @@ -1354,7 +1354,7 @@ export class Vpc extends VpcBase { throw new Error('supply at most one of ipAddresses or cidr'); } - this.ipAddresses = props.ipAddresses ?? new Cidr(cidrBlock); + this.ipAddresses = props.ipAddresses ?? IpAddresses.cidr(cidrBlock); this.dnsHostnamesEnabled = props.enableDnsHostnames == null ? true : props.enableDnsHostnames; this.dnsSupportEnabled = props.enableDnsSupport == null ? true : props.enableDnsSupport; diff --git a/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts index 8f2e0e88ecd15..83119f2605e57 100644 --- a/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts @@ -22,7 +22,7 @@ describe('Cidr vpc allocation', () => { }); -describe('IpAddresses.Cidr subnets allocation', () => { +describe('IpAddresses.cidr subnets allocation', () => { const cidrProps = '10.0.0.0/16'; From ee1bb7453072254182f7ca40d083faee61470384 Mon Sep 17 00:00:00 2001 From: Neil Baillie Date: Tue, 25 Oct 2022 21:30:33 +0100 Subject: [PATCH 16/20] pushing From cfb536a6f03e2e08249ebab066b257149b87f8e8 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 26 Oct 2022 12:27:49 +0200 Subject: [PATCH 17/20] Rename `awsIpam` -> `awsIpamAllocation`, rewrite README a bit --- packages/@aws-cdk/aws-ec2/README.md | 55 +++++++++---------- packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts | 16 +++--- .../@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts | 2 +- .../aws-ec2/test/ip-addresses.test.ts | 24 ++++---- 4 files changed, 49 insertions(+), 48 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 7af54c6dd8bf6..a05db53e2b167 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -219,50 +219,43 @@ provider.connections.allowFrom(ec2.Peer.ipv4('1.2.3.4/8'), ec2.Port.tcp(80)); ### Ip Address Management -The VPC spans a supernet IP range, which contains the non-overlapping IPs of it's contained subnets. Possible sources for this IP range are: +The VPC spans a supernet IP range, which contains the non-overlapping IPs of its contained subnets. Possible sources for this IP range are: * You specify an IP range directly by specifying a CIDR * You allocate an IP range of a given size automatically from AWS IPAM -If you don't specify anything, by default the Vpc will allocate the 10.0.0.0/16 address range which will be exhaustively spread across all subnets in the subnet configuration. This behavior can be changed (see "Allocating an IP range from AWS IPAM" bellow). +By default the Vpc will allocate the `10.0.0.0/16` address range which will be exhaustively spread across all subnets in the subnet configuration. This behavior can be changed by passing an object that implements `IIpAddresses` to the `ipAddress` property of a Vpc. See the subsequent sections for the options. -Be aware that if you don't specify 'ipAddresses' the address space will be fully allocated! If you predict you may need to add more subnet groups later, add them early on and set reserved: true (see the "Advanced Subnet Configuration" section for more information). +Be aware that if you don't explicitly reserve subnet groups in `subnetConfiguration`, the address space will be fully allocated! If you predict you may need to add more subnet groups later, add them early on and set `reserved: true` (see the "Advanced Subnet Configuration" section for more information). -To facilitate options for flexibility in the allocation and use of IP space within Vpc and Subnet including strategy and implementation for the allocation, Vpc utilizes 'ipAddresses'. +#### Specifying a CIDR directly -By default, the Vpc construct will create and use IpAddresses.cidr for you if you do not set the Vpc ipAddresses property. IpAddresses.cidr is an implementation of the Original CDK Vpc and Subnet IP address allocation strategy and implementation. - -You must supply at most one of 'ipAddresses' or 'cidr' to Vpc. - -#### Specifying an IP range via a CIDR - IpAddresses.cidr - -IpAddresses.cidr allows you to define a Cidr range directly for your Vpc. - -IpAddresses.cidr will first try to allocated space from the Vpc Cidr any Subnets that explicitly have a `cidrMask` as part of a SubnetConfiguration, this includes reserved subnets, after this any remaining space is divided fully between the rest of the required subnets. - -When using IpAddresses.cidr concrete Cidr values are generated in the synthesized CloudFormation template. +Use `IpAddresses.cidr` to define a Cidr range for your Vpc directly in code: ```ts -import { IpAddresses } from ''@aws-cdk/aws-ec2''; +import { IpAddresses } from '@aws-cdk/aws-ec2'; new ec2.Vpc(stack, 'TheVPC', { ipAddresses: IpAddresses.cidr('10.0.1.0/20') }); ``` -#### Allocating an IP range from AWS IPAM - IpAddresses.awsIpam +Space will be allocated to subnets in the following order: -IpAddresses.awsIpam uses Amazon VPC IP Address Manager (IPAM) to allocated the Cidr for the Vpc. For information on Amazon VPC IP Address Manager please see the [official documentation](https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html). +- First, spaces is allocated for all subnets groups that explicitly have a `cidrMask` set as part of their configuration (including reserved subnets). +- Afterwards, any remaining space is divided evenly between the rest of the subnets (if any). -AWS Ipam requires a `ipv4IpamPoolId` be set to the Amazon VPC IP Address Manager Pool Id used for the Vpc Cidr allocation, additionally an `ipv4NetmaskLength` must be set, which defines the size of cidr that will be requested from the Pool at deploy time by the CloudFormation engine. +The argument to `IpAddresses.cidr` may not be a token, and concrete Cidr values are generated in the synthesized CloudFormation template. -Subnets are allocated locally of a size defined by `defaultSubnetIpv4NetmaskLength` property or by using any explicit `cidrMask` from a supplied SubnetConfiguration. The provider AwsIpam dose not attempt to allocated any remaining space in the Vpc's Cidr space. +#### Allocating an IP range from AWS IPAM + +Amazon VPC IP Address Manager (IPAM) manages a large IP space, from which chunks can be allocated for use in the Vpc. For information on Amazon VPC IP Address Manager please see the [official documentation](https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html). An example of allocating from AWS IPAM looks like this: ```ts -import { IpAddresses } from ''@aws-cdk/aws-ec2''; +import { IpAddresses } from '@aws-cdk/aws-ec2'; new ec2.Vpc(stack, 'TheVPC', { - ipAddresses: IpAddresses.awsIpam({ + ipAddresses: IpAddresses.awsIpamAllocation({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24 @@ -270,7 +263,13 @@ new ec2.Vpc(stack, 'TheVPC', { }); ``` -When using IpAddresses.awsIpam the final Cidr allocation for Vpc and Subnets are unknown at synth time. Because of this Subnet Cidr values are synthesized as CloudFormation Intrinsic functions representing their offset within the Vpc Cidr space and not concrete values. +`IpAddresses.awsIpamAllocation` requires the following: + +- `ipv4IpamPoolId`, the id of an IPAM Pool from which the VPC range should be allocated. +- `ipv4NetmaskLength`, the size of the IP range that will be requested from the Pool at deploy time. +- `defaultSubnetIpv4NetmaskLength`, the size of subnets in groups that don't have `cidrMask` set. + +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. ### Advanced Subnet Configuration @@ -1003,11 +1002,11 @@ new ec2.Instance(this, 'Instance2', { }), }); -// AWS Linux 2 with kernel 5.x +// AWS Linux 2 with kernel 5.x new ec2.Instance(this, 'Instance3', { vpc, instanceType, - machineImage: new ec2.AmazonLinuxImage({ + machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, kernel: ec2.AmazonLinuxKernel.KERNEL5_X, }), @@ -1017,7 +1016,7 @@ new ec2.Instance(this, 'Instance3', { new ec2.Instance(this, 'Instance4', { vpc, instanceType, - machineImage: new ec2.AmazonLinuxImage({ + machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2022, }), }); @@ -1462,9 +1461,9 @@ asset.grantRead(instance.role); ### Persisting user data By default, EC2 UserData is run once on only the first time that an instance is started. It is possible to make the -user data script run on every start of the instance. +user data script run on every start of the instance. -When creating a Windows UserData you can use the `persist` option to set whether or not to add +When creating a Windows UserData you can use the `persist` option to set whether or not to add `true` [to the user data script](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-user-data.html#user-data-scripts). it can be used as follows: ```ts diff --git a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts index 50040cb3f41c9..c94acb3ee52c7 100644 --- a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts +++ b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts @@ -13,7 +13,7 @@ export abstract class IpAddresses { * VPC Cidr is supplied at creation and subnets are calculated locally * */ - public static cidr(cidrBlock: string): IpAddresses { + public static cidr(cidrBlock: string): IIpAddresses { return new Cidr(cidrBlock); } @@ -24,7 +24,7 @@ export abstract class IpAddresses { * * @see https://docs.aws.amazon.com/vpc/latest/ipam/what-it-is-ipam.html */ - public static awsIpam(props: AwsIpamProps): IpAddresses { + public static awsIpamAllocation(props: AwsIpamProps): IIpAddresses { return new AwsIpam(props); } @@ -41,6 +41,8 @@ export abstract class IpAddresses { * Don't call this directly, the VPC will call it automatically. */ public abstract allocateSubnetsCidr(input: AllocateCidrRequest): SubnetIpamOptions; + + protected constructor() { } } /** @@ -193,7 +195,7 @@ export interface AwsIpamProps { * * ```ts * new ec2.Vpc(stack, 'TheVPC', { - * ipAddresses: new IpAddresses.awsIpam({ + * ipAddresses: IpAddresses.awsIpamAllocation({ * ipv4IpamPoolId: pool.ref, * ipv4NetmaskLength: 18, * defaultSubnetIpv4NetmaskLength: 24 @@ -203,7 +205,8 @@ export interface AwsIpamProps { * */ class AwsIpam implements IIpAddresses { - constructor(private readonly props: AwsIpamProps) {} + constructor(private readonly props: AwsIpamProps) { + } /** * Allocates Vpc Cidr. called when creating a Vpc using AwsIpam. @@ -258,7 +261,7 @@ class AwsIpam implements IIpAddresses { * * ```ts * new ec2.Vpc(stack, 'TheVPC', { - * ipAddresses: new ec2.IpAddresses.cidr('10.0.1.0/20') + * ipAddresses: ec2.IpAddresses.cidr('10.0.1.0/20') * }); * ``` * @@ -267,7 +270,6 @@ class Cidr implements IIpAddresses { private readonly networkBuilder: NetworkBuilder; constructor(private readonly cidrBlock: string) { - 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)'); } @@ -317,4 +319,4 @@ class Cidr implements IIpAddresses { allocatedSubnets: allocatedSubnets, }; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts index f032042472b48..7b4f3296c09f4 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.vpc-ipam.ts @@ -36,7 +36,7 @@ const pool = new CfnIPAMPool(stack, 'Pool', { pool.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN); const awsIpamVpc = new Vpc(stack, 'AwsIpamVpc', { - ipAddresses: IpAddresses.awsIpam({ + ipAddresses: IpAddresses.awsIpamAllocation({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24, diff --git a/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts index 83119f2605e57..4df3561fd4b82 100644 --- a/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/ip-addresses.test.ts @@ -105,17 +105,17 @@ describe('AwsIpam vpc allocation', () => { }; test('AwsIpam returns cidrBlock as undefined', () => { - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); expect(ipAddresses.allocateVpcCidr().cidrBlock).toBeUndefined; }); test('AwsIpam returns the correct vpc ipv4IpamPoolId', () => { - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); expect(ipAddresses.allocateVpcCidr().ipv4IpamPoolId).toEqual('ipam-pool-0111222333444'); }); test('AwsIpam returns the correct vpc ipv4NetmaskLength', () => { - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); expect(ipAddresses.allocateVpcCidr().ipv4NetmaskLength).toEqual(22); }); @@ -129,7 +129,7 @@ describe('AwsIpam subnets allocation', () => { }; test('AwsIpam returns subnet allocations as 2x TOKEN, when you do not give a cidr for the subnets', () => { - const ipAddresses = IpAddresses.awsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const ipAddresses = IpAddresses.awsIpamAllocation({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', @@ -155,7 +155,7 @@ describe('AwsIpam subnets allocation', () => { }); test('AwsIpam returns subnet allocations as 2x TOKEN, when you provide a cidr for the subnets', () => { - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', @@ -183,7 +183,7 @@ describe('AwsIpam subnets allocation', () => { }); test('AwsIpam returns subnet allocations as 2x TOKEN, when you mix provide and non provided cidr for the subnets', () => { - const ipAddresses = IpAddresses.awsIpam({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); + const ipAddresses = IpAddresses.awsIpamAllocation({ defaultSubnetIpv4NetmaskLength: 24, ...awsIpamProps }); const allocations = ipAddresses.allocateSubnetsCidr({ requestedSubnets: [{ availabilityZone: 'dummyAz1', @@ -263,7 +263,7 @@ describe('AwsIpam Vpc Integration', () => { ipv4NetmaskLength: 22, }; - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses });}).toThrow(/If you have not set a cidr for all subnets in this case you must set a defaultCidrMask in AwsIpam Options/);; @@ -279,7 +279,7 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 24, }; - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses }); @@ -300,7 +300,7 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 24, }; - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses }); @@ -354,7 +354,7 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 17, }; - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); expect(() => {new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses });}).toThrow('IP space of size /18 not big enough to allocate subnets of sizes /17,/17,/17,/17');; @@ -370,7 +370,7 @@ describe('AwsIpam Vpc Integration', () => { defaultSubnetIpv4NetmaskLength: 17, }; - const ipAddresses = IpAddresses.awsIpam(awsIpamProps); + const ipAddresses = IpAddresses.awsIpamAllocation(awsIpamProps); new Vpc(stack, 'VpcNetwork', { ipAddresses: ipAddresses, @@ -408,4 +408,4 @@ describe('AwsIpam Vpc Integration', () => { }); -}); \ No newline at end of file +}); From 1369c2c4a10ec51a5d473c34521b4f5f4db7415e Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 26 Oct 2022 12:30:18 +0200 Subject: [PATCH 18/20] `IpAddresses` class is factory only, no need to have abstracts --- packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts index c94acb3ee52c7..4a6cbc6df7ea7 100644 --- a/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts +++ b/packages/@aws-cdk/aws-ec2/lib/ip-addresses.ts @@ -6,7 +6,7 @@ import { SubnetConfiguration } from './vpc'; /** * An abstract Provider of IpAddresses */ -export abstract class IpAddresses { +export class IpAddresses { /** * Used to provide local Ip Address Management services for your VPC * @@ -28,21 +28,7 @@ export abstract class IpAddresses { return new AwsIpam(props); } - /** - * Called by the VPC to retrieve VPC options from the Ipam - * - * Don't call this directly, the VPC will call it automatically. - */ - public abstract allocateVpcCidr(): VpcIpamOptions; - - /** - * Called by the VPC to retrieve Subnet options from the Ipam - * - * Don't call this directly, the VPC will call it automatically. - */ - public abstract allocateSubnetsCidr(input: AllocateCidrRequest): SubnetIpamOptions; - - protected constructor() { } + private constructor() { } } /** @@ -50,12 +36,16 @@ export abstract class IpAddresses { */ export interface IIpAddresses { /** - * Allocates Cidr for Vpc + * Called by the VPC to retrieve VPC options from the Ipam + * + * Don't call this directly, the VPC will call it automatically. */ allocateVpcCidr(): VpcIpamOptions; /** - * Allocates Cidr for Subnets + * Called by the VPC to retrieve Subnet options from the Ipam + * + * Don't call this directly, the VPC will call it automatically. */ allocateSubnetsCidr(input: AllocateCidrRequest): SubnetIpamOptions; } From d28048349a66317dd7de15e0571e2c859537a1be Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 26 Oct 2022 12:34:18 +0200 Subject: [PATCH 19/20] Make examples compile --- packages/@aws-cdk/aws-ec2/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index a05db53e2b167..e7b2abfa59810 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -236,7 +236,7 @@ Use `IpAddresses.cidr` to define a Cidr range for your Vpc directly in code: import { IpAddresses } from '@aws-cdk/aws-ec2'; new ec2.Vpc(stack, 'TheVPC', { - ipAddresses: IpAddresses.cidr('10.0.1.0/20') + ipAddresses: ec2.IpAddresses.cidr('10.0.1.0/20') }); ``` @@ -254,8 +254,10 @@ Amazon VPC IP Address Manager (IPAM) manages a large IP space, from which chunks ```ts import { IpAddresses } from '@aws-cdk/aws-ec2'; +declare const pool: ec2.CfnIPAMPool; + new ec2.Vpc(stack, 'TheVPC', { - ipAddresses: IpAddresses.awsIpamAllocation({ + ipAddresses: ec2.IpAddresses.awsIpamAllocation({ ipv4IpamPoolId: pool.ref, ipv4NetmaskLength: 18, defaultSubnetIpv4NetmaskLength: 24 From 64370054204abb34b33e0b18c1aa8c04342ecfa1 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 26 Oct 2022 16:01:27 +0200 Subject: [PATCH 20/20] Markdownlint --- packages/@aws-cdk/aws-ec2/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index e7b2abfa59810..43048983fd705 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -242,8 +242,8 @@ new ec2.Vpc(stack, 'TheVPC', { Space will be allocated to subnets in the following order: -- First, spaces is allocated for all subnets groups that explicitly have a `cidrMask` set as part of their configuration (including reserved subnets). -- Afterwards, any remaining space is divided evenly between the rest of the subnets (if any). +* First, spaces is allocated for all subnets groups that explicitly have a `cidrMask` set as part of their configuration (including reserved subnets). +* Afterwards, any remaining space is divided evenly between the rest of the subnets (if any). The argument to `IpAddresses.cidr` may not be a token, and concrete Cidr values are generated in the synthesized CloudFormation template. @@ -267,9 +267,9 @@ new ec2.Vpc(stack, 'TheVPC', { `IpAddresses.awsIpamAllocation` requires the following: -- `ipv4IpamPoolId`, the id of an IPAM Pool from which the VPC range should be allocated. -- `ipv4NetmaskLength`, the size of the IP range that will be requested from the Pool at deploy time. -- `defaultSubnetIpv4NetmaskLength`, the size of subnets in groups that don't have `cidrMask` set. +* `ipv4IpamPoolId`, the id of an IPAM Pool from which the VPC range should be allocated. +* `ipv4NetmaskLength`, the size of the IP range that will be requested from the Pool at deploy time. +* `defaultSubnetIpv4NetmaskLength`, the size of subnets in groups that don't have `cidrMask` set. 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.