From e878f9c5fd503615a4d65a3f866e80cff001a309 Mon Sep 17 00:00:00 2001 From: Daniel Neilson <53624638+ddneilson@users.noreply.github.com> Date: Sun, 9 Aug 2020 06:04:17 -0500 Subject: [PATCH 01/43] fix(docdb): `autoMinorVersionUpgrade` property was not set to `true` by default as stated in the docstring (#9505) Fixes https://github.com/aws/aws-cdk/issues/9494 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-docdb/lib/instance.ts | 2 +- .../@aws-cdk/aws-docdb/test/instance.test.ts | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-docdb/lib/instance.ts b/packages/@aws-cdk/aws-docdb/lib/instance.ts index cdefa1d155f9f..7c69c626703d4 100644 --- a/packages/@aws-cdk/aws-docdb/lib/instance.ts +++ b/packages/@aws-cdk/aws-docdb/lib/instance.ts @@ -203,7 +203,7 @@ export class DatabaseInstance extends DatabaseInstanceBase implements IDatabaseI const instance = new CfnDBInstance(this, 'Resource', { dbClusterIdentifier: props.cluster.clusterIdentifier, dbInstanceClass: `db.${props.instanceClass}`, - autoMinorVersionUpgrade: props.autoMinorVersionUpgrade, + autoMinorVersionUpgrade: props.autoMinorVersionUpgrade ?? true, availabilityZone: props.availabilityZone, dbInstanceIdentifier: props.dbInstanceName, preferredMaintenanceWindow: props.preferredMaintenanceWindow, diff --git a/packages/@aws-cdk/aws-docdb/test/instance.test.ts b/packages/@aws-cdk/aws-docdb/test/instance.test.ts index b36d6af554ef1..197e2e296fd8d 100644 --- a/packages/@aws-cdk/aws-docdb/test/instance.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/instance.test.ts @@ -24,6 +24,34 @@ describe('DatabaseInstance', () => { Properties: { DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, DBInstanceClass: EXPECTED_SYNTH_INSTANCE_TYPE, + AutoMinorVersionUpgrade: true, + }, + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }, ResourcePart.CompleteDefinition)); + }); + + test.each([ + [undefined, true], + [true, true], + [false, false], + ])('check that autoMinorVersionUpdate works: %p', (given: boolean | undefined, expected: boolean) => { + // GIVEN + const stack = testStack(); + + // WHEN + new DatabaseInstance(stack, 'Instance', { + cluster: stack.cluster, + instanceClass: SINGLE_INSTANCE_TYPE, + autoMinorVersionUpgrade: given, + }); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBInstance', { + Properties: { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: EXPECTED_SYNTH_INSTANCE_TYPE, + AutoMinorVersionUpgrade: expected, }, DeletionPolicy: 'Retain', UpdateReplacePolicy: 'Retain', From 938f326c14029687159e1b553d621d1418bf3d64 Mon Sep 17 00:00:00 2001 From: Peter Reid Date: Sun, 9 Aug 2020 12:26:28 +0100 Subject: [PATCH 02/43] chore(cloudfront): Add expanded description of webAclId parameter (#9395) Add a detailed description of this parameter as per the existing AWS API documentation to save confusion for users Fixes #9393 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index 21392c625aad6..b2fc472adfd46 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -646,7 +646,14 @@ export interface CloudFrontWebDistributionProps { /** * Unique identifier that specifies the AWS WAF web ACL to associate with this CloudFront distribution. + * + * To specify a web ACL created using the latest version of AWS WAF, use the ACL ARN, for example + * `arn:aws:wafv2:us-east-1:123456789012:global/webacl/ExampleWebACL/473e64fd-f30b-4765-81a0-62ad96dd167a`. + * + * To specify a web ACL created using AWS WAF Classic, use the ACL ID, for example `473e64fd-f30b-4765-81a0-62ad96dd167a`. + * * @see https://docs.aws.amazon.com/waf/latest/developerguide/what-is-aws-waf.html + * @see https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html#API_CreateDistribution_RequestParameters. * * @default - No AWS Web Application Firewall web access control list (web ACL). */ From f098014e0e9e49b2cc6a30922b8b0545e9c45e5e Mon Sep 17 00:00:00 2001 From: Matthew Bonig Date: Sun, 9 Aug 2020 23:46:59 -0600 Subject: [PATCH 03/43] feat(readme): include partitions.io cdk board in "getting help" (#9541) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d12001783d663..a406ed66cfe48 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ You may also find help on these community resources: and tag it with `aws-cdk` * Come join the AWS CDK community on [Gitter](https://gitter.im/awslabs/aws-cdk) * Talk in the CDK channel of the [AWS Developers Slack workspace](https://awsdevelopers.slack.com) (invite required) +* Check out the [partitions.io board](https://partitions.io/cdk) ### Roadmap From dd0f4cb55bd9d7a95ccc9691ba33dab658d60e97 Mon Sep 17 00:00:00 2001 From: Eli Polonsky Date: Mon, 10 Aug 2020 09:08:44 +0300 Subject: [PATCH 04/43] fix(eks): private endpoint access doesn't work with `Vpc.fromLookup` (#9544) Fixes #9542 Related #5383 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-eks/lib/cluster.ts | 30 +++++- .../@aws-cdk/aws-eks/test/test.cluster.ts | 101 +++++++++++++++++- 2 files changed, 128 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index f572bc6e35c98..dbc34c53353af 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -1018,13 +1018,20 @@ export class Cluster extends Resource implements ICluster { }; if (!this.endpointAccess._config.publicAccess) { + + const privateSubents = this.selectPrivateSubnets().slice(0, 16); + + if (privateSubents.length === 0) { + throw new Error('Vpc must contain private subnets to configure private endpoint access'); + } + // endpoint access is private only, we need to attach the // provider to the VPC so that it can access the cluster. providerProps = { ...providerProps, vpc: this.vpc, // lambda can only be accociated with max 16 subnets and they all need to be private. - vpcSubnets: {subnets: this.selectPrivateSubnets().slice(0, 16)}, + vpcSubnets: {subnets: privateSubents}, securityGroups: [this.kubctlProviderSecurityGroup], }; } @@ -1049,7 +1056,26 @@ export class Cluster extends Resource implements ICluster { const privateSubnets: ec2.ISubnet[] = []; for (const placement of this.vpcSubnets) { - privateSubnets.push(...this.vpc.selectSubnets(placement).subnets.filter(s => s instanceof ec2.PrivateSubnet)); + + for (const subnet of this.vpc.selectSubnets(placement).subnets) { + + if (this.vpc.privateSubnets.includes(subnet)) { + // definitely private, take it. + privateSubnets.push(subnet); + continue; + } + + if (this.vpc.publicSubnets.includes(subnet)) { + // definitely public, skip it. + continue; + } + + // neither public and nor private - what is it then? this means its a subnet instance that was explicitly passed + // in the subnet selection. since ISubnet doesn't contain information on type, we have to assume its private and let it + // fail at deploy time :\ (its better than filtering it out and preventing a possibly successful deployment) + privateSubnets.push(subnet); + } + } return privateSubnets; diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index aaf1d0a2de124..576e4081e83c0 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -1400,6 +1400,105 @@ export = { 'endpoint access': { + 'private endpoint access fails if selected subnets are empty'(test: Test) { + + const { stack } = testFixture(); + + test.throws(() => { + new eks.Cluster(stack, 'Cluster', { + vpc: new ec2.Vpc(stack, 'Vpc'), + version: CLUSTER_VERSION, + endpointAccess: eks.EndpointAccess.PRIVATE, + vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }], + }); + }, /Vpc must contain private subnets to configure private endpoint access/); + + test.done(); + }, + + 'private endpoint access selects only private subnets from looked up vpc'(test: Test) { + + const vpcId = 'vpc-12345'; + // can't use the regular fixture because it also adds a VPC to the stack, which prevents + // us from setting context. + const stack = new cdk.Stack(new cdk.App(), 'Stack', { + env: { + account: '11112222', + region: 'us-east-1', + }, + }); + stack.node.setContext(`vpc-provider:account=${stack.account}:filter.vpc-id=${vpcId}:region=${stack.region}:returnAsymmetricSubnets=true`, { + vpcId: vpcId, + vpcCidrBlock: '10.0.0.0/16', + subnetGroups: [ + { + name: 'Private', + type: 'Private', + subnets: [ + { + subnetId: 'subnet-private-in-us-east-1a', + cidr: '10.0.1.0/24', + availabilityZone: 'us-east-1a', + routeTableId: 'rtb-06068e4c4049921ef', + }, + ], + }, + { + name: 'Public', + type: 'Public', + subnets: [ + { + subnetId: 'subnet-public-in-us-east-1c', + cidr: '10.0.0.0/24', + availabilityZone: 'us-east-1c', + routeTableId: 'rtb-0ff08e62195198dbb', + }, + ], + }, + ], + }); + const vpc = ec2.Vpc.fromLookup(stack, 'Vpc', { + vpcId: vpcId, + }); + + new eks.Cluster(stack, 'Cluster', { + vpc, + version: CLUSTER_VERSION, + endpointAccess: eks.EndpointAccess.PRIVATE, + }); + + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const template = expect(nested).value; + + test.deepEqual(template.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds, [ + 'subnet-private-in-us-east-1a', + ]); + + test.done(); + }, + + 'private endpoint access considers specific subnet selection'(test: Test) { + const { stack } = testFixture(); + new eks.Cluster(stack, 'Cluster', { + version: CLUSTER_VERSION, endpointAccess: + eks.EndpointAccess.PRIVATE, + vpcSubnets: [{subnets: [ec2.PrivateSubnet.fromSubnetAttributes(stack, 'Private1', { + subnetId: 'subnet1', + availabilityZone: 'us-east-1a', + })]}], + }); + + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const template = expect(nested).value; + + test.deepEqual(template.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds, [ + 'subnet1', + ]); + + test.done(); + + }, + 'can configure private endpoint access'(test: Test) { // GIVEN const { stack } = testFixture(); @@ -1669,4 +1768,4 @@ export = { }, }, -}; +}; \ No newline at end of file From d3861ee5ba12cd56c94137558114b0d78db6d7ab Mon Sep 17 00:00:00 2001 From: Neta Nir Date: Mon, 10 Aug 2020 03:18:38 -0700 Subject: [PATCH 05/43] chore(core): document how to override availability zones (#9504) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/README.md | 18 ++++++++++++++++++ packages/@aws-cdk/core/lib/stack.ts | 4 +++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 991a2e39c8316..668943296ac4d 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -90,6 +90,24 @@ itself to 2 Availability Zones. Therefore, to get the VPC to spread over 3 or more availability zones, you must specify the environment where the stack will be deployed. +You can gain full control over the availability zones selection strategy by overriding the Stack's [`get availabilityZones()`](https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/core/lib/stack.ts) method: + +```ts +class MyStack extends Stack { + + get availabilityZones(): string[] { + return ['us-west-2a', 'us-west-2b']; + } + + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + ... + } +} +``` + +Note that overriding the `get availabilityZones()` method will override the default behavior for all constructs defined within the Stack. + ### Choosing subnets for resources When creating resources that create Elastic Network Interfaces (such as diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index f913377b54a20..53433d0823fbe 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -571,7 +571,7 @@ export class Stack extends Construct implements ITaggable { } /** - * Returnst the list of AZs that are availability in the AWS environment + * Returns the list of AZs that are available in the AWS environment * (account/region) associated with this stack. * * If the stack is environment-agnostic (either account and/or region are @@ -582,6 +582,8 @@ export class Stack extends Construct implements ITaggable { * If they are not available in the context, returns a set of dummy values and * reports them as missing, and let the CLI resolve them by calling EC2 * `DescribeAvailabilityZones` on the target environment. + * + * To specify a different strategy for selecting availability zones override this method. */ public get availabilityZones(): string[] { // if account/region are tokens, we can't obtain AZs through the context From 74e839189b2e9b028e6b9944884bf8fe73de2429 Mon Sep 17 00:00:00 2001 From: Daniel Neilson <53624638+ddneilson@users.noreply.github.com> Date: Mon, 10 Aug 2020 05:40:36 -0500 Subject: [PATCH 06/43] fix(ec2): Volume grants have an overly complicated API (#9115) I designed & wrote the code for the L2 Volume construct. My design for the `grantAttachVolumeByResourceTag()` and `grantDetachVolumeByResourceTag()` is flawed. Those functions have three design requirements: 1) To allow an instance to attach a Volume to itself; 2) To allow an instance to attach multiple, different, volumes; and 3) To allow the same volume to be attached to different instances via separate grants without clobbering other grants. Since the implementation mechanism for this is a `ResourceTag` condition on the policy, the later two requirements mean that we must have both a unique tag key and a unique tag value for each separate permission grant (i.e. separate call to the volume's grant function). The original design had the tag key being derived from only the volume, the tag value from only the instance(s), and allowed for overriding the tag key via a parameter to allow for the same volume to attach to multiple instances over separate grants. In hindsight, we should be deriving both the resource tag and value from the combination of the instance(s) and the volume's unique properties. This completely eliminates the need for the tag key override. The current design results in code like: ```ts // To be able to mount the *same* volume to multiple instances we must provide a tag suffix to the permission grant // that is unique to this particular combination of volume + mount target. function hashUniqueIds(resources: IConstruct[]): string { const md5 = crypto.createHash('md5'); resources.forEach(res => md5.update(res.node.uniqueId)); return md5.digest('hex'); } this.props.blockVolume.grantAttachVolumeByResourceTag(target.grantPrincipal, [target], hashUniqueIds([target, this.props.blockVolume])); ``` It is much more desirable for this to be simply: ```ts this.props.blockVolume.grantAttachVolumeByResourceTag(target.grantPrincipal, [target]); ``` Resolves: #9114 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/lib/volume.ts | 21 ++++-------- packages/@aws-cdk/aws-ec2/test/volume.test.ts | 34 +++++++++---------- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/lib/volume.ts b/packages/@aws-cdk/aws-ec2/lib/volume.ts index d379ae6622b1f..e33c32a9d63b6 100644 --- a/packages/@aws-cdk/aws-ec2/lib/volume.ts +++ b/packages/@aws-cdk/aws-ec2/lib/volume.ts @@ -290,14 +290,10 @@ export interface IVolume extends IResource { * given the ability to AttachVolume if both the Volume and the destination Instance have that * tag applied to them. * - * If you need to call this method multiple times on different sets of constructs, then provide a - * unique `tagKeySuffix` for each call; failure to do so will result in an inability to attach this - * volume to some of the grants because it will overwrite the tag. - * * @param grantee the principal being granted permission. * @param constructs The list of constructs that will have the generated resource tag applied to them. * @param tagKeySuffix A suffix to use on the generated Tag key in place of the generated hash value. - * Defaults to a hash calculated from this volume. + * Defaults to a hash calculated from this volume and list of constructs. (DEPRECATED) */ grantAttachVolumeByResourceTag(grantee: IGrantable, constructs: Construct[], tagKeySuffix?: string): Grant; @@ -324,7 +320,7 @@ export interface IVolume extends IResource { * @param grantee the principal being granted permission. * @param constructs The list of constructs that will have the generated resource tag applied to them. * @param tagKeySuffix A suffix to use on the generated Tag key in place of the generated hash value. - * Defaults to a hash calculated from this volume. + * Defaults to a hash calculated from this volume and list of constructs. (DEPRECATED) */ grantDetachVolumeByResourceTag(grantee: IGrantable, constructs: Construct[], tagKeySuffix?: string): Grant; } @@ -497,8 +493,8 @@ abstract class VolumeBase extends Resource implements IVolume { } public grantAttachVolumeByResourceTag(grantee: IGrantable, constructs: Construct[], tagKeySuffix?: string): Grant { - const tagKey = `VolumeGrantAttach-${tagKeySuffix ?? this.stringHash(this.node.uniqueId)}`; - const tagValue = this.calculateResourceTagValue(constructs); + const tagValue = this.calculateResourceTagValue([this, ...constructs]); + const tagKey = `VolumeGrantAttach-${tagKeySuffix ?? tagValue.slice(0,10).toUpperCase()}`; const grantCondition: { [key: string]: string } = {}; grantCondition[`ec2:ResourceTag/${tagKey}`] = tagValue; @@ -526,8 +522,8 @@ abstract class VolumeBase extends Resource implements IVolume { } public grantDetachVolumeByResourceTag(grantee: IGrantable, constructs: Construct[], tagKeySuffix?: string): Grant { - const tagKey = `VolumeGrantDetach-${tagKeySuffix ?? this.stringHash(this.node.uniqueId)}`; - const tagValue = this.calculateResourceTagValue(constructs); + const tagValue = this.calculateResourceTagValue([this, ...constructs]); + const tagKey = `VolumeGrantDetach-${tagKeySuffix ?? tagValue.slice(0,10).toUpperCase()}`; const grantCondition: { [key: string]: string } = {}; grantCondition[`ec2:ResourceTag/${tagKey}`] = tagValue; @@ -558,11 +554,6 @@ abstract class VolumeBase extends Resource implements IVolume { return resourceArns; } - private stringHash(value: string): string { - const md5 = crypto.createHash('md5').update(value).digest('hex'); - return md5.slice(0, 8).toUpperCase(); - } - private calculateResourceTagValue(constructs: Construct[]): string { const md5 = crypto.createHash('md5'); constructs.forEach(construct => md5.update(construct.node.uniqueId)); diff --git a/packages/@aws-cdk/aws-ec2/test/volume.test.ts b/packages/@aws-cdk/aws-ec2/test/volume.test.ts index 0600d201755a7..05ae59f8d7a0f 100644 --- a/packages/@aws-cdk/aws-ec2/test/volume.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/volume.test.ts @@ -739,7 +739,7 @@ nodeunitShim({ ], Condition: { 'ForAnyValue:StringEquals': { - 'ec2:ResourceTag/VolumeGrantAttach-BD7A9717': 'd9a17c1c9e8ef6866e4dbeef41c741b2', + 'ec2:ResourceTag/VolumeGrantAttach-B2376B2BDA': 'b2376b2bda65cb40f83c290dd844c4aa', }, }, }], @@ -748,8 +748,8 @@ nodeunitShim({ cdkExpect(stack).to(haveResourceLike('AWS::EC2::Volume', { Tags: [ { - Key: 'VolumeGrantAttach-BD7A9717', - Value: 'd9a17c1c9e8ef6866e4dbeef41c741b2', + Key: 'VolumeGrantAttach-B2376B2BDA', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], }, ResourcePart.Properties)); @@ -757,8 +757,8 @@ nodeunitShim({ Tags: [ {}, { - Key: 'VolumeGrantAttach-BD7A9717', - Value: 'd9a17c1c9e8ef6866e4dbeef41c741b2', + Key: 'VolumeGrantAttach-B2376B2BDA', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], }, ResourcePart.Properties)); @@ -816,7 +816,7 @@ nodeunitShim({ ], Condition: { 'ForAnyValue:StringEquals': { - 'ec2:ResourceTag/VolumeGrantAttach-TestSuffix': 'd9a17c1c9e8ef6866e4dbeef41c741b2', + 'ec2:ResourceTag/VolumeGrantAttach-TestSuffix': 'b2376b2bda65cb40f83c290dd844c4aa', }, }, }], @@ -826,7 +826,7 @@ nodeunitShim({ Tags: [ { Key: 'VolumeGrantAttach-TestSuffix', - Value: 'd9a17c1c9e8ef6866e4dbeef41c741b2', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], }, ResourcePart.Properties)); @@ -835,11 +835,10 @@ nodeunitShim({ {}, { Key: 'VolumeGrantAttach-TestSuffix', - Value: 'd9a17c1c9e8ef6866e4dbeef41c741b2', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], }, ResourcePart.Properties)); - test.done(); }, @@ -1051,7 +1050,7 @@ nodeunitShim({ ], Condition: { 'ForAnyValue:StringEquals': { - 'ec2:ResourceTag/VolumeGrantDetach-BD7A9717': 'd9a17c1c9e8ef6866e4dbeef41c741b2', + 'ec2:ResourceTag/VolumeGrantDetach-B2376B2BDA': 'b2376b2bda65cb40f83c290dd844c4aa', }, }, }], @@ -1060,8 +1059,8 @@ nodeunitShim({ cdkExpect(stack).to(haveResourceLike('AWS::EC2::Volume', { Tags: [ { - Key: 'VolumeGrantDetach-BD7A9717', - Value: 'd9a17c1c9e8ef6866e4dbeef41c741b2', + Key: 'VolumeGrantDetach-B2376B2BDA', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], }, ResourcePart.Properties)); @@ -1069,8 +1068,8 @@ nodeunitShim({ Tags: [ {}, { - Key: 'VolumeGrantDetach-BD7A9717', - Value: 'd9a17c1c9e8ef6866e4dbeef41c741b2', + Key: 'VolumeGrantDetach-B2376B2BDA', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], }, ResourcePart.Properties)); @@ -1128,7 +1127,7 @@ nodeunitShim({ ], Condition: { 'ForAnyValue:StringEquals': { - 'ec2:ResourceTag/VolumeGrantDetach-TestSuffix': 'd9a17c1c9e8ef6866e4dbeef41c741b2', + 'ec2:ResourceTag/VolumeGrantDetach-TestSuffix': 'b2376b2bda65cb40f83c290dd844c4aa', }, }, }], @@ -1138,7 +1137,7 @@ nodeunitShim({ Tags: [ { Key: 'VolumeGrantDetach-TestSuffix', - Value: 'd9a17c1c9e8ef6866e4dbeef41c741b2', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], }, ResourcePart.Properties)); @@ -1147,11 +1146,10 @@ nodeunitShim({ {}, { Key: 'VolumeGrantDetach-TestSuffix', - Value: 'd9a17c1c9e8ef6866e4dbeef41c741b2', + Value: 'b2376b2bda65cb40f83c290dd844c4aa', }, ], }, ResourcePart.Properties)); - test.done(); }, From d9723bb9b0457a2c89e41116354ba6df18b605c9 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Mon, 10 Aug 2020 13:03:54 +0200 Subject: [PATCH 07/43] chore(lambda-nodejs): move all directories references to commands (#9547) This is a prerequisite to offer a way out of Docker. We don't want to keep references to bundling directories in the `package.json` configuration because they have no meaning when running locally. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-lambda-nodejs/lib/bundling.ts | 31 +++++++++------- .../aws-lambda-nodejs/test/bundling.test.ts | 7 ++-- .../test/integ.dependencies.expected.json | 18 +++++----- .../test/integ.function.expected.json | 36 +++++++++---------- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index b612709216d41..7ff7b06ef741c 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -137,8 +137,7 @@ export class Bundling { // Configure target in package.json for Parcel packageJsonManager.update({ - 'cdk-lambda': `${cdk.AssetStaging.BUNDLING_OUTPUT_DIR}/index.js`, - 'targets': { + targets: { 'cdk-lambda': { context: 'node', includeNodeModules: includeNodeModules ?? true, @@ -153,16 +152,24 @@ export class Bundling { // Entry file path relative to container path const containerEntryPath = path.join(cdk.AssetStaging.BUNDLING_INPUT_DIR, path.relative(projectRoot, path.resolve(options.entry))); - const parcelCommand = [ - '$(node -p "require.resolve(\'parcel\')")', // Parcel is not globally installed, find its "bin" - 'build', containerEntryPath.replace(/\\/g, '/'), // Always use POSIX paths in the container - '--target', 'cdk-lambda', - '--no-autoinstall', - '--no-scope-hoist', - ...options.cacheDir - ? ['--cache-dir', '/parcel-cache'] - : [], - ].join(' '); + const distFile = path.basename(options.entry).replace(/\.ts$/, '.js'); + const parcelCommand = chain([ + [ + '$(node -p "require.resolve(\'parcel\')")', // Parcel is not globally installed, find its "bin" + 'build', containerEntryPath.replace(/\\/g, '/'), // Always use POSIX paths in the container + '--target', 'cdk-lambda', + '--dist-dir', cdk.AssetStaging.BUNDLING_OUTPUT_DIR, // Output bundle in /asset-output (will have the same name as the entry) + '--no-autoinstall', + '--no-scope-hoist', + ...options.cacheDir + ? ['--cache-dir', '/parcel-cache'] + : [], + ].join(' '), + // Always rename dist file to index.js because Lambda doesn't support filenames + // with multiple dots and we can end up with multiple dots when using automatic + // entry lookup + `mv ${cdk.AssetStaging.BUNDLING_OUTPUT_DIR}/${distFile} ${cdk.AssetStaging.BUNDLING_OUTPUT_DIR}/index.js`, + ]); let installer = Installer.NPM; let lockfile: string | undefined; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts index cc7dac2261023..535d9ec0d0541 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -46,7 +46,7 @@ test('Parcel bundling', () => { workingDirectory: '/asset-input/folder', command: [ 'bash', '-c', - '$(node -p "require.resolve(\'parcel\')") build /asset-input/folder/entry.ts --target cdk-lambda --no-autoinstall --no-scope-hoist --cache-dir /parcel-cache', + '$(node -p "require.resolve(\'parcel\')") build /asset-input/folder/entry.ts --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist --cache-dir /parcel-cache && mv /asset-output/entry.js /asset-output/index.js', ], }), }); @@ -55,8 +55,7 @@ test('Parcel bundling', () => { const call = writeFileSyncMock.mock.calls[0]; expect(call[0]).toMatch('package.json'); expect(JSON.parse(call[1])).toEqual(expect.objectContaining({ - 'cdk-lambda': '/asset-output/index.js', - 'targets': { + targets: { 'cdk-lambda': { context: 'node', includeNodeModules: { @@ -107,7 +106,7 @@ test('Parcel bundling with externals and dependencies', () => { bundling: expect.objectContaining({ command: [ 'bash', '-c', - '$(node -p "require.resolve(\'parcel\')") build /asset-input/folder/entry.ts --target cdk-lambda --no-autoinstall --no-scope-hoist && mv /asset-input/.package.json /asset-output/package.json && cd /asset-output && npm install', + '$(node -p "require.resolve(\'parcel\')") build /asset-input/folder/entry.ts --target cdk-lambda --dist-dir /asset-output --no-autoinstall --no-scope-hoist && mv /asset-output/entry.js /asset-output/index.js && mv /asset-input/.package.json /asset-output/package.json && cd /asset-output && npm install', ], }), }); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json index 24a997c991c49..94fa1f25ec7f1 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2S3BucketB430E8D1" + "Ref": "AssetParametersf94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722eS3Bucket64177146" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2S3VersionKeyF30AC4DF" + "Ref": "AssetParametersf94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722eS3VersionKeyF8E0F956" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2S3VersionKeyF30AC4DF" + "Ref": "AssetParametersf94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722eS3VersionKeyF8E0F956" } ] } @@ -92,17 +92,17 @@ } }, "Parameters": { - "AssetParametersebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2S3BucketB430E8D1": { + "AssetParametersf94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722eS3Bucket64177146": { "Type": "String", - "Description": "S3 bucket for asset \"ebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2\"" + "Description": "S3 bucket for asset \"f94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722e\"" }, - "AssetParametersebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2S3VersionKeyF30AC4DF": { + "AssetParametersf94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722eS3VersionKeyF8E0F956": { "Type": "String", - "Description": "S3 key for asset version \"ebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2\"" + "Description": "S3 key for asset version \"f94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722e\"" }, - "AssetParametersebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2ArtifactHash6E38BF0B": { + "AssetParametersf94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722eArtifactHash8BE4F210": { "Type": "String", - "Description": "Artifact hash for asset \"ebe4053f51756bfe12e0de8e07d4b67c2c2a4346090e1ad12622987dabe996b2\"" + "Description": "Artifact hash for asset \"f94126eb364c953df28028e19ee70b3d0c2ac3fa9b88d0f5475e95978cb2722e\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json index 5139b6c84d89b..e88132489f9ae 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.function.expected.json @@ -36,7 +36,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091S3Bucket3A595CE7" + "Ref": "AssetParametersd2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636S3Bucket24297AFB" }, "S3Key": { "Fn::Join": [ @@ -49,7 +49,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091S3VersionKey708CAAF7" + "Ref": "AssetParametersd2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636S3VersionKeyF5D64812" } ] } @@ -62,7 +62,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091S3VersionKey708CAAF7" + "Ref": "AssetParametersd2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636S3VersionKeyF5D64812" } ] } @@ -126,7 +126,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941S3BucketB102419B" + "Ref": "AssetParametersa3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6baS3Bucket796E4856" }, "S3Key": { "Fn::Join": [ @@ -139,7 +139,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941S3VersionKey468D1E85" + "Ref": "AssetParametersa3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6baS3VersionKeyBCA2678F" } ] } @@ -152,7 +152,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941S3VersionKey468D1E85" + "Ref": "AssetParametersa3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6baS3VersionKeyBCA2678F" } ] } @@ -182,29 +182,29 @@ } }, "Parameters": { - "AssetParameters12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091S3Bucket3A595CE7": { + "AssetParametersd2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636S3Bucket24297AFB": { "Type": "String", - "Description": "S3 bucket for asset \"12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091\"" + "Description": "S3 bucket for asset \"d2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636\"" }, - "AssetParameters12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091S3VersionKey708CAAF7": { + "AssetParametersd2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636S3VersionKeyF5D64812": { "Type": "String", - "Description": "S3 key for asset version \"12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091\"" + "Description": "S3 key for asset version \"d2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636\"" }, - "AssetParameters12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091ArtifactHashECEF4AD0": { + "AssetParametersd2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636ArtifactHashBEFC24E5": { "Type": "String", - "Description": "Artifact hash for asset \"12f1d42878e237685b5a4cb717404fa08bf4aa659ccb573c7916f7e818ffc091\"" + "Description": "Artifact hash for asset \"d2bd5cfe4dc136ef456512a7d596b27f2da67bf81f6f0e20d8e0328f5fc3e636\"" }, - "AssetParameters5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941S3BucketB102419B": { + "AssetParametersa3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6baS3Bucket796E4856": { "Type": "String", - "Description": "S3 bucket for asset \"5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941\"" + "Description": "S3 bucket for asset \"a3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6ba\"" }, - "AssetParameters5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941S3VersionKey468D1E85": { + "AssetParametersa3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6baS3VersionKeyBCA2678F": { "Type": "String", - "Description": "S3 key for asset version \"5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941\"" + "Description": "S3 key for asset version \"a3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6ba\"" }, - "AssetParameters5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941ArtifactHashF56A9434": { + "AssetParametersa3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6baArtifactHashFF9F139E": { "Type": "String", - "Description": "Artifact hash for asset \"5383ed2a06cec74db0261318b2a3d648f26aa1a48e5e34ff40fb218e9eaf9941\"" + "Description": "Artifact hash for asset \"a3bab04de14ffc364f4351c7019d484a5e36b66f74fc6b33a3ea208c20a8d6ba\"" } } } \ No newline at end of file From a311428d6013a1486585979a010f4105b0e0f97a Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 10 Aug 2020 15:11:08 +0300 Subject: [PATCH 08/43] feat(core): new APIs for Aspects and Tags (#9558) In [CDK 2.0], the `applyAspect` API will be removed and instead will be accessible through a "trait" pattern: Aspects.of(scope).add(aspect) Similarly, we are normalizing the tagging API to use the same pattern: Tags.of(scope).add(x, y) Tags.of(scope).remove(x) The existing APIs are still supported but marked as @deprecated. Related: https://github.com/aws/aws-cdk-rfcs/issues/192, See [Design]. [CDK 2.0]: https://github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md [Design]: https://github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#02-aspects ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/core/lib/aspect.ts | 47 +++++++++++++++++++ .../@aws-cdk/core/lib/construct-compat.ts | 15 ++++-- .../@aws-cdk/core/lib/private/synthesis.ts | 36 +++++++------- packages/@aws-cdk/core/lib/tag-aspect.ts | 43 +++++++++++++++-- packages/@aws-cdk/core/test/test.aspect.ts | 10 ++-- packages/@aws-cdk/core/test/test.stack.ts | 4 +- packages/@aws-cdk/core/test/test.stage.ts | 6 +-- .../@aws-cdk/core/test/test.tag-aspect.ts | 40 ++++++++-------- 8 files changed, 145 insertions(+), 56 deletions(-) diff --git a/packages/@aws-cdk/core/lib/aspect.ts b/packages/@aws-cdk/core/lib/aspect.ts index 17534e2139f0f..3bca67a12aa6d 100644 --- a/packages/@aws-cdk/core/lib/aspect.ts +++ b/packages/@aws-cdk/core/lib/aspect.ts @@ -1,5 +1,7 @@ import { IConstruct } from './construct-compat'; +const ASPECTS_SYMBOL = Symbol('cdk-aspects'); + /** * Represents an Aspect */ @@ -9,3 +11,48 @@ export interface IAspect { */ visit(node: IConstruct): void; } + +/** + * Aspects can be applied to CDK tree scopes and can operate on the tree before + * synthesis. + */ +export class Aspects { + + /** + * Returns the `Aspects` object associated with a construct scope. + * @param scope The scope for which these aspects will apply. + */ + public static of(scope: IConstruct): Aspects { + let aspects = (scope as any)[ASPECTS_SYMBOL]; + if (!aspects) { + aspects = new Aspects(scope); + + Object.defineProperty(scope, ASPECTS_SYMBOL, { + value: aspects, + configurable: false, + enumerable: false, + }); + } + return aspects; + } + + // TODO(2.0): private readonly _aspects = new Array(); + private constructor(private readonly scope: IConstruct) { } + + /** + * Adds an aspect to apply this scope before synthesis. + * @param aspect The aspect to add. + */ + public add(aspect: IAspect) { + // TODO(2.0): this._aspects.push(aspect); + this.scope.node._actualNode.applyAspect(aspect); + } + + /** + * The list of aspects which were directly applied on this scope. + */ + public get aspects(): IAspect[] { + // TODO(2.0): return [ ...this._aspects ]; + return [ ...(this.scope.node._actualNode as any)._aspects ]; // clone + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index e689d3a837619..315fa8a38232f 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -13,7 +13,7 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; import * as constructs from 'constructs'; -import { IAspect } from './aspect'; +import { IAspect, Aspects } from './aspect'; import { IDependable } from './dependency'; import { Token } from './token'; @@ -267,7 +267,13 @@ export class ConstructNode { */ public readonly _actualNode: constructs.Node; + /** + * The Construct class that hosts this API. + */ + private readonly host: Construct; + constructor(host: Construct, scope: IConstruct, id: string) { + this.host = host; this._actualNode = new constructs.Node(host, scope, id); // store a back reference on _actualNode so we can our ConstructNode from it @@ -433,9 +439,12 @@ export class ConstructNode { } /** - * Applies the aspect to this Constructs node + * DEPRECATED: Applies the aspect to this Constructs node + * + * @deprecated This API is going to be removed in the next major version of + * the AWS CDK. Please use `Aspects.of(scope).add()` instead. */ - public applyAspect(aspect: IAspect): void { this._actualNode.applyAspect(aspect); } + public applyAspect(aspect: IAspect): void { Aspects.of(this.host).add(aspect); } /** * All parent scopes of this construct. diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index 296ba171efde9..77f0bacb7004a 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -1,5 +1,6 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as constructs from 'constructs'; +import { Aspects, IAspect } from '../aspect'; import { Construct, IConstruct, SynthesisOptions, ValidationError } from '../construct-compat'; import { Stack } from '../stack'; import { Stage, StageSynthesisOptions } from '../stage'; @@ -60,26 +61,35 @@ function synthNestedAssemblies(root: IConstruct, options: StageSynthesisOptions) * twice for the same construct. */ function invokeAspects(root: IConstruct) { + const invokedByPath: { [nodePath: string]: IAspect[] } = { }; + let nestedAspectWarning = false; recurse(root, []); function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) { - // hackery to be able to access some private members with strong types (yack!) - const node: NodeWithAspectPrivatesHangingOut = construct.node._actualNode as any; - - const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects]; - const nodeAspectsCount = node._aspects.length; + const node = construct.node; + const aspects = Aspects.of(construct); + const allAspectsHere = [...inheritedAspects ?? [], ...aspects.aspects]; + const nodeAspectsCount = aspects.aspects.length; for (const aspect of allAspectsHere) { - if (node.invokedAspects.includes(aspect)) { continue; } + let invoked = invokedByPath[node.path]; + if (!invoked) { + invoked = invokedByPath[node.path] = []; + } + + if (invoked.includes(aspect)) { continue; } aspect.visit(construct); + // if an aspect was added to the node while invoking another aspect it will not be invoked, emit a warning // the `nestedAspectWarning` flag is used to prevent the warning from being emitted for every child - if (!nestedAspectWarning && nodeAspectsCount !== node._aspects.length) { + if (!nestedAspectWarning && nodeAspectsCount !== aspects.aspects.length) { construct.node.addWarning('We detected an Aspect was added via another Aspect, and will not be applied'); nestedAspectWarning = true; } - node.invokedAspects.push(aspect); + + // mark as invoked for this node + invoked.push(aspect); } for (const child of construct.node.children) { @@ -180,13 +190,3 @@ interface IProtectedConstructMethods extends IConstruct { */ onPrepare(): void; } - -/** - * The constructs Node type, but with some aspects-related fields public. - * - * Hackery! - */ -type NodeWithAspectPrivatesHangingOut = Omit & { - readonly invokedAspects: constructs.IAspect[]; - readonly _aspects: constructs.IAspect[]; -}; \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/tag-aspect.ts b/packages/@aws-cdk/core/lib/tag-aspect.ts index a0c8445cd84a8..3c8fd7b01a6b8 100644 --- a/packages/@aws-cdk/core/lib/tag-aspect.ts +++ b/packages/@aws-cdk/core/lib/tag-aspect.ts @@ -1,5 +1,5 @@ // import * as cxapi from '@aws-cdk/cx-api'; -import { IAspect } from './aspect'; +import { IAspect, Aspects } from './aspect'; import { Construct, IConstruct } from './construct-compat'; import { ITaggable, TagManager } from './tag-manager'; @@ -86,17 +86,21 @@ abstract class TagBase implements IAspect { export class Tag extends TagBase { /** - * add tags to the node of a construct and all its the taggable children + * DEPRECATED: add tags to the node of a construct and all its the taggable children + * + * @deprecated use `Tags.of(scope).add()` */ public static add(scope: Construct, key: string, value: string, props: TagProps = {}) { - scope.node.applyAspect(new Tag(key, value, props)); + Tags.of(scope).add(key, value, props); } /** - * remove tags to the node of a construct and all its the taggable children + * DEPRECATED: remove tags to the node of a construct and all its the taggable children + * + * @deprecated use `Tags.of(scope).remove()` */ public static remove(scope: Construct, key: string, props: TagProps = {}) { - scope.node.applyAspect(new RemoveTag(key, props)); + Tags.of(scope).remove(key, props); } /** @@ -126,6 +130,35 @@ export class Tag extends TagBase { } } +/** + * Manages AWS tags for all resources within a construct scope. + */ +export class Tags { + /** + * Returns the tags API for this scope. + * @param scope The scope + */ + public static of(scope: IConstruct): Tags { + return new Tags(scope); + } + + private constructor(private readonly scope: IConstruct) { } + + /** + * add tags to the node of a construct and all its the taggable children + */ + public add(key: string, value: string, props: TagProps = {}) { + Aspects.of(this.scope).add(new Tag(key, value, props)); + } + + /** + * remove tags to the node of a construct and all its the taggable children + */ + public remove(key: string, props: TagProps = {}) { + Aspects.of(this.scope).add(new RemoveTag(key, props)); + } +} + /** * The RemoveTag Aspect will handle removing tags from this node and children */ diff --git a/packages/@aws-cdk/core/test/test.aspect.ts b/packages/@aws-cdk/core/test/test.aspect.ts index 5b13b2a547b5b..90294a86055a7 100644 --- a/packages/@aws-cdk/core/test/test.aspect.ts +++ b/packages/@aws-cdk/core/test/test.aspect.ts @@ -1,7 +1,7 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { Test } from 'nodeunit'; import { App } from '../lib'; -import { IAspect } from '../lib/aspect'; +import { IAspect, Aspects } from '../lib/aspect'; import { Construct, IConstruct } from '../lib/construct-compat'; class MyConstruct extends Construct { @@ -29,7 +29,7 @@ export = { 'Aspects are invoked only once'(test: Test) { const app = new App(); const root = new MyConstruct(app, 'MyConstruct'); - root.node.applyAspect(new VisitOnce()); + Aspects.of(root).add(new VisitOnce()); app.synth(); test.deepEqual(root.visitCounter, 1); app.synth(); @@ -41,9 +41,9 @@ export = { const app = new App(); const root = new MyConstruct(app, 'MyConstruct'); const child = new MyConstruct(root, 'ChildConstruct'); - root.node.applyAspect({ + Aspects.of(root).add({ visit(construct: IConstruct) { - construct.node.applyAspect({ + Aspects.of(construct).add({ visit(inner: IConstruct) { inner.node.addMetadata('test', 'would-be-ignored'); }, @@ -62,7 +62,7 @@ export = { const app = new App(); const root = new MyConstruct(app, 'Construct'); const child = new MyConstruct(root, 'ChildConstruct'); - root.node.applyAspect(new MyAspect()); + Aspects.of(root).add(new MyAspect()); app.synth(); test.deepEqual(root.node.metadata[0].type, 'foo'); test.deepEqual(root.node.metadata[0].data, 'bar'); diff --git a/packages/@aws-cdk/core/test/test.stack.ts b/packages/@aws-cdk/core/test/test.stack.ts index c6a3be31af013..4eb7ab164b29c 100644 --- a/packages/@aws-cdk/core/test/test.stack.ts +++ b/packages/@aws-cdk/core/test/test.stack.ts @@ -2,7 +2,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import { Test } from 'nodeunit'; import { App, CfnCondition, CfnInclude, CfnOutput, CfnParameter, - CfnResource, Construct, Lazy, ScopedAws, Stack, Tag, validateString, ISynthesisSession } from '../lib'; + CfnResource, Construct, Lazy, ScopedAws, Stack, validateString, ISynthesisSession, Tags } from '../lib'; import { Intrinsic } from '../lib/private/intrinsic'; import { resolveReferences } from '../lib/private/refs'; import { PostResolveToken } from '../lib/util'; @@ -840,7 +840,7 @@ export = { const stack2 = new Stack(stack1, 'stack2'); // WHEN - Tag.add(app, 'foo', 'bar'); + Tags.of(app).add('foo', 'bar'); // THEN const asm = app.synth(); diff --git a/packages/@aws-cdk/core/test/test.stage.ts b/packages/@aws-cdk/core/test/test.stage.ts index 4f5e5f02d0542..d93b8d2c08c38 100644 --- a/packages/@aws-cdk/core/test/test.stage.ts +++ b/packages/@aws-cdk/core/test/test.stage.ts @@ -1,6 +1,6 @@ import * as cxapi from '@aws-cdk/cx-api'; import { Test } from 'nodeunit'; -import { App, CfnResource, Construct, IAspect, IConstruct, Stack, Stage } from '../lib'; +import { App, CfnResource, Construct, IAspect, IConstruct, Stack, Stage, Aspects } from '../lib'; export = { 'Stack inherits unspecified part of the env from Stage'(test: Test) { @@ -148,7 +148,7 @@ export = { // WHEN const aspect = new TouchingAspect(); - stack.node.applyAspect(aspect); + Aspects.of(stack).add(aspect); // THEN app.synth(); @@ -168,7 +168,7 @@ export = { // WHEN const aspect = new TouchingAspect(); - app.node.applyAspect(aspect); + Aspects.of(app).add(aspect); // THEN app.synth(); diff --git a/packages/@aws-cdk/core/test/test.tag-aspect.ts b/packages/@aws-cdk/core/test/test.tag-aspect.ts index cd533bd537e67..ed21a5930b5b4 100644 --- a/packages/@aws-cdk/core/test/test.tag-aspect.ts +++ b/packages/@aws-cdk/core/test/test.tag-aspect.ts @@ -1,5 +1,5 @@ import { Test } from 'nodeunit'; -import { CfnResource, CfnResourceProps, Construct, RemoveTag, Stack, Tag, TagManager, TagType } from '../lib'; +import { CfnResource, CfnResourceProps, Construct, RemoveTag, Stack, Tag, TagManager, TagType, Aspects, Tags } from '../lib'; import { synthesize } from '../lib/private/synthesis'; class TaggableResource extends CfnResource { @@ -54,7 +54,7 @@ export = { const map = new MapTaggableResource(res, 'MapFakeResource', { type: 'AWS::Fake::Thing', }); - res.node.applyAspect(new Tag('foo', 'bar')); + Aspects.of(res).add(new Tag('foo', 'bar')); synthesize(root); @@ -72,10 +72,10 @@ export = { const res2 = new TaggableResource(res, 'FakeResource', { type: 'AWS::Fake::Thing', }); - res.node.applyAspect(new Tag('foo', 'bar')); - res.node.applyAspect(new Tag('foo', 'foobar')); - res.node.applyAspect(new Tag('foo', 'baz')); - res2.node.applyAspect(new Tag('foo', 'good')); + Aspects.of(res).add(new Tag('foo', 'bar')); + Aspects.of(res).add(new Tag('foo', 'foobar')); + Aspects.of(res).add(new Tag('foo', 'baz')); + Aspects.of(res2).add(new Tag('foo', 'good')); synthesize(root); test.deepEqual(res.tags.renderTags(), [{key: 'foo', value: 'baz'}]); test.deepEqual(res2.tags.renderTags(), [{key: 'foo', value: 'good'}]); @@ -96,10 +96,10 @@ export = { const map = new MapTaggableResource(res, 'MapFakeResource', { type: 'AWS::Fake::Thing', }); - root.node.applyAspect(new Tag('root', 'was here')); - res.node.applyAspect(new Tag('first', 'there is only 1')); - res.node.applyAspect(new RemoveTag('root')); - res.node.applyAspect(new RemoveTag('doesnotexist')); + Aspects.of(root).add(new Tag('root', 'was here')); + Aspects.of(res).add(new Tag('first', 'there is only 1')); + Aspects.of(res).add(new RemoveTag('root')); + Aspects.of(res).add(new RemoveTag('doesnotexist')); synthesize(root); test.deepEqual(res.tags.renderTags(), [{key: 'first', value: 'there is only 1'}]); @@ -123,10 +123,10 @@ export = { const map = new MapTaggableResource(res, 'MapFakeResource', { type: 'AWS::Fake::Thing', }); - Tag.add(root, 'root', 'was here'); - Tag.add(res, 'first', 'there is only 1'); - Tag.remove(res, 'root'); - Tag.remove(res, 'doesnotexist'); + Tags.of(root).add('root', 'was here'); + Tags.of(res).add('first', 'there is only 1'); + Tags.of(res).remove('root'); + Tags.of(res).remove('doesnotexist'); synthesize(root); @@ -142,7 +142,7 @@ export = { type: 'AWS::Fake::Thing', }); - res.node.applyAspect(new Tag('foo', 'bar')); + Aspects.of(res).add(new Tag('foo', 'bar')); synthesize(root); test.deepEqual(res.tags.renderTags(), [{key: 'foo', value: 'bar'}]); synthesize(root); @@ -159,8 +159,8 @@ export = { const res2 = new TaggableResource(res, 'FakeResource', { type: 'AWS::Fake::Thing', }); - res.node.applyAspect(new RemoveTag('key')); - res2.node.applyAspect(new Tag('key', 'value')); + Aspects.of(res).add(new RemoveTag('key')); + Aspects.of(res2).add(new Tag('key', 'value')); synthesize(root); test.deepEqual(res.tags.renderTags(), undefined); test.deepEqual(res2.tags.renderTags(), undefined); @@ -174,8 +174,8 @@ export = { const res2 = new TaggableResource(res, 'FakeResource', { type: 'AWS::Fake::Thing', }); - res.node.applyAspect(new RemoveTag('key', {priority: 0})); - res2.node.applyAspect(new Tag('key', 'value')); + Aspects.of(res).add(new RemoveTag('key', {priority: 0})); + Aspects.of(res2).add(new Tag('key', 'value')); synthesize(root); test.deepEqual(res.tags.renderTags(), undefined); test.deepEqual(res2.tags.renderTags(), [{key: 'key', value: 'value'}]); @@ -218,7 +218,7 @@ export = { ], }, }); - aspectBranch.node.applyAspect(new Tag('aspects', 'rule')); + Aspects.of(aspectBranch).add(new Tag('aspects', 'rule')); synthesize(root); test.deepEqual(aspectBranch.testProperties().tags, [{key: 'aspects', value: 'rule'}, {key: 'cfn', value: 'is cool'}]); test.deepEqual(asgResource.testProperties().tags, [ From 5c01da8d82f77e0241890101258aace2dac1902d Mon Sep 17 00:00:00 2001 From: barticus Date: Mon, 10 Aug 2020 22:53:17 +1000 Subject: [PATCH 09/43] fix(pipelines): manual approval of changeset uses wrong ordering (#9508) From `addApplication` or `addStackArtifactDeployment` method. Currently, when calling `addStackArtifactDeployment`, you can pass in `AddStackOptions`, but the `executeRunOrder` property is not respected later in the process where `DeployCdkStackAction.fromStackArtifact` is called. From addApplication, this property is used when manualApprovals has been opted in to, but as it is not respected, it results in bug #9101 Fixes #9101 (I think!) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/pipelines/lib/stage.ts | 7 +++--- .../pipelines/test/stack-ordering.test.ts | 25 ++++++++++++++++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/pipelines/lib/stage.ts b/packages/@aws-cdk/pipelines/lib/stage.ts index 6b379f686fe2e..dd5aa28c5e50e 100644 --- a/packages/@aws-cdk/pipelines/lib/stage.ts +++ b/packages/@aws-cdk/pipelines/lib/stage.ts @@ -184,7 +184,7 @@ export class CdkStage extends Construct { if (this._prepared) { return; } this._prepared = true; - for (const { prepareRunOrder: runOrder, stackArtifact } of this.stacksToDeploy) { + for (const { prepareRunOrder, stackArtifact, executeRunOrder } of this.stacksToDeploy) { const artifact = this.host.stackOutputArtifact(stackArtifact.id); this.pipelineStage.addAction(DeployCdkStackAction.fromStackArtifact(this, stackArtifact, { @@ -192,7 +192,8 @@ export class CdkStage extends Construct { cloudAssemblyInput: this.cloudAssemblyArtifact, output: artifact, outputFileName: artifact ? 'outputs.json' : undefined, - prepareRunOrder: runOrder, + prepareRunOrder, + executeRunOrder, })); } } @@ -387,4 +388,4 @@ interface DeployStackCommand { prepareRunOrder: number; executeRunOrder: number; stackArtifact: cxapi.CloudFormationStackArtifact; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts b/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts index e755572c78544..45d0cb76bf6b8 100644 --- a/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts +++ b/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts @@ -55,6 +55,29 @@ test('multiple independent stacks go in parallel', () => { }); }); +test('manual approval is inserted in correct location', () => { + // WHEN + pipeline.addApplicationStage(new TwoStackApp(app, 'MyApp'), { + manualApprovals: true, + }); + + // THEN + expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Stages: arrayWith({ + Name: 'MyApp', + Actions: sortedByRunOrder([ + objectLike({ Name: 'Stack1.Prepare' }), + objectLike({ Name: 'ManualApproval' }), + objectLike({ Name: 'Stack1.Deploy' }), + objectLike({ Name: 'Stack2.Prepare' }), + objectLike({ Name: 'ManualApproval2' }), + objectLike({ Name: 'Stack2.Deploy' }), + ]), + }), + }); +}); + + class TwoStackApp extends Stage { constructor(scope: Construct, id: string, props?: StageProps) { super(scope, id, props); @@ -80,4 +103,4 @@ class ThreeStackApp extends Stage { stack3.addDependency(stack1); stack3.addDependency(stack2); } -} \ No newline at end of file +} From f78c3469522006d38078db6effc4556d44da9747 Mon Sep 17 00:00:00 2001 From: Robert Djurasaj Date: Mon, 10 Aug 2020 07:14:47 -0600 Subject: [PATCH 10/43] fix(efs): LifecyclePolicy of AFTER_7_DAYS is not applied (#9475) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #9474 (see for details). ```ts const fileSystem = new efs.FileSystem(this, "EFS", { removalPolicy: cdk.RemovalPolicy.DESTROY, lifecyclePolicy: efs.LifecyclePolicy.AFTER_7_DAYS, vpc, }); ``` Old behavior: ```bash npm run build; cdk synth | grep -r -n1 "AFTER_"; cdk diff > demo@0.1.0 build /Users/robertd/code/demo > tsc Stack EFSDemoTest Resources [~] AWS::EFS::FileSystem EFS EFSBAA8953A └─ [-] LifecyclePolicies └─ [{"TransitionToIA":"AFTER_14_DAYS"}] ``` **New (expected) behavior:** 🎆 🥳 🍾 ```bash npm run build; cdk synth | grep -r -n1 "AFTER_"; cdk diff > demo@0.1.0 build /Users/robertd/demo > tsc (standard input)-327- LifecyclePolicies: (standard input):328: - TransitionToIA: AFTER_7_DAYS (standard input)-329- UpdateReplacePolicy: Delete Stack EFSDemoTest Resources [~] AWS::EFS::FileSystem EFS EFSBAA8953A └─ [~] LifecyclePolicies └─ @@ -1,5 +1,5 @@ [ ] [ [ ] { [-] "TransitionToIA": "AFTER_14_DAYS" [+] "TransitionToIA": "AFTER_7_DAYS" [ ] } [ ] ] ``` ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-efs/README.md | 2 +- packages/@aws-cdk/aws-efs/lib/efs-file-system.ts | 14 ++++++-------- .../@aws-cdk/aws-efs/test/efs-file-system.test.ts | 6 +++--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/@aws-cdk/aws-efs/README.md b/packages/@aws-cdk/aws-efs/README.md index 01d766117a6b1..f1082eeddbc83 100644 --- a/packages/@aws-cdk/aws-efs/README.md +++ b/packages/@aws-cdk/aws-efs/README.md @@ -68,7 +68,7 @@ fileSystem.connections.allowDefaultPortFrom(instance); In order to automatically mount this file system during instance launch, following code can be used as reference: -``` +```ts const vpc = new ec2.Vpc(this, 'VPC'); const fileSystem = new efs.FileSystem(this, 'MyEfsFileSystem', { diff --git a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts index 8103ee40bae79..854503f388f7d 100644 --- a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts +++ b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts @@ -13,27 +13,27 @@ export enum LifecyclePolicy { /** * After 7 days of not being accessed. */ - AFTER_7_DAYS, + AFTER_7_DAYS = 'AFTER_7_DAYS', /** * After 14 days of not being accessed. */ - AFTER_14_DAYS, + AFTER_14_DAYS = 'AFTER_14_DAYS', /** * After 30 days of not being accessed. */ - AFTER_30_DAYS, + AFTER_30_DAYS = 'AFTER_30_DAYS', /** * After 60 days of not being accessed. */ - AFTER_60_DAYS, + AFTER_60_DAYS = 'AFTER_60_DAYS', /** * After 90 days of not being accessed. */ - AFTER_90_DAYS + AFTER_90_DAYS = 'AFTER_90_DAYS' } /** @@ -247,9 +247,7 @@ export class FileSystem extends Resource implements IFileSystem { const filesystem = new CfnFileSystem(this, 'Resource', { encrypted: props.encrypted, kmsKeyId: (props.kmsKey ? props.kmsKey.keyId : undefined), - lifecyclePolicies: (props.lifecyclePolicy ? Array.of({ - transitionToIa: LifecyclePolicy[props.lifecyclePolicy], - } as CfnFileSystem.LifecyclePolicyProperty) : undefined), + lifecyclePolicies: (props.lifecyclePolicy ? [{ transitionToIa: props.lifecyclePolicy }] : undefined), performanceMode: props.performanceMode, throughputMode: props.throughputMode, provisionedThroughputInMibps: props.provisionedThroughputPerSecond?.toMebibytes(), diff --git a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts index 42fa89ee8d9ae..5104c069ec061 100644 --- a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts +++ b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts @@ -75,16 +75,16 @@ test('encrypted file system is created correctly with custom KMS', () => { })); }); -test('file system is created correctly with life cycle property', () => { +test('file system is created correctly with a life cycle property', () => { // WHEN new FileSystem(stack, 'EfsFileSystem', { vpc, - lifecyclePolicy: LifecyclePolicy.AFTER_14_DAYS, + lifecyclePolicy: LifecyclePolicy.AFTER_7_DAYS, }); // THEN expectCDK(stack).to(haveResource('AWS::EFS::FileSystem', { LifecyclePolicies: [{ - TransitionToIA: 'AFTER_14_DAYS', + TransitionToIA: 'AFTER_7_DAYS', }], })); }); From bd45f3419e24d6a9d9989a0efeacf2233866100b Mon Sep 17 00:00:00 2001 From: Justin Dray Date: Mon, 10 Aug 2020 23:40:07 +1000 Subject: [PATCH 11/43] fix(pipelines): CodeBuild images have (too) old Node version (#9446) fixes #9070 This change moves CDK pipelines from standard build image 1.0 to 4.0 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .gitignore | 2 ++ .../lib/actions/deploy-cdk-stack-action.ts | 2 +- .../lib/actions/publish-assets-action.ts | 6 ++++-- .../lib/actions/update-pipeline-action.ts | 1 + .../pipelines/lib/private/asset-manifest.ts | 2 +- .../pipelines/lib/private/construct-internals.ts | 2 +- .../pipelines/lib/synths/simple-synth-action.ts | 6 +++--- .../lib/validation/shell-script-action.ts | 1 + packages/@aws-cdk/pipelines/test/builds.test.ts | 15 +++++++++++++++ .../test/integ.pipeline-with-assets.expected.json | 10 +++++----- .../pipelines/test/integ.pipeline.expected.json | 6 +++--- .../pipelines/test/pipeline-assets.test.ts | 8 ++++++++ packages/@aws-cdk/pipelines/test/pipeline.test.ts | 6 ++++++ packages/@aws-cdk/pipelines/test/testutil.ts | 4 ++-- .../@aws-cdk/pipelines/test/validation.test.ts | 9 +++++++++ 15 files changed, 62 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 74312eef24f20..055b85911775d 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,5 @@ yarn-error.log # Parcel default cache directory .parcel-cache +# Cloud9 +.c9 diff --git a/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts b/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts index 790f18db764af..c13dad054c790 100644 --- a/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts +++ b/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts @@ -1,3 +1,4 @@ +import * as path from 'path'; import * as cfn from '@aws-cdk/aws-cloudformation'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as cpactions from '@aws-cdk/aws-codepipeline-actions'; @@ -5,7 +6,6 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { Arn, Construct, Fn, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import * as path from 'path'; import { appOf, assemblyBuilderOf } from '../private/construct-internals'; /** diff --git a/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts b/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts index c9fb4a334c6f2..a16862c20d014 100644 --- a/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts +++ b/packages/@aws-cdk/pipelines/lib/actions/publish-assets-action.ts @@ -81,6 +81,10 @@ export class PublishAssetsAction extends Construct implements codepipeline.IActi const project = new codebuild.PipelineProject(this, 'Default', { projectName: this.props.projectName, + environment: { + buildImage: codebuild.LinuxBuildImage.STANDARD_4_0, + privileged: (props.assetType === AssetType.DOCKER_IMAGE) ? true : undefined, + }, buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', phases: { @@ -92,8 +96,6 @@ export class PublishAssetsAction extends Construct implements codepipeline.IActi }, }, }), - // Needed to perform Docker builds - environment: props.assetType === AssetType.DOCKER_IMAGE ? { privileged: true } : undefined, role: props.role, }); diff --git a/packages/@aws-cdk/pipelines/lib/actions/update-pipeline-action.ts b/packages/@aws-cdk/pipelines/lib/actions/update-pipeline-action.ts index e7b19ac860102..c17c7826c3a7c 100644 --- a/packages/@aws-cdk/pipelines/lib/actions/update-pipeline-action.ts +++ b/packages/@aws-cdk/pipelines/lib/actions/update-pipeline-action.ts @@ -54,6 +54,7 @@ export class UpdatePipelineAction extends Construct implements codepipeline.IAct const selfMutationProject = new codebuild.PipelineProject(this, 'SelfMutation', { projectName: props.projectName, + environment: { buildImage: codebuild.LinuxBuildImage.STANDARD_4_0 }, buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', phases: { diff --git a/packages/@aws-cdk/pipelines/lib/private/asset-manifest.ts b/packages/@aws-cdk/pipelines/lib/private/asset-manifest.ts index 752c7c242bc48..66b9b78d9cbb0 100644 --- a/packages/@aws-cdk/pipelines/lib/private/asset-manifest.ts +++ b/packages/@aws-cdk/pipelines/lib/private/asset-manifest.ts @@ -1,7 +1,7 @@ // FIXME: copied from `ckd-assets`, because this tool needs to read the asset manifest aswell. -import { AssetManifest, DockerImageDestination, DockerImageSource, FileDestination, FileSource, Manifest } from '@aws-cdk/cloud-assembly-schema'; import * as fs from 'fs'; import * as path from 'path'; +import { AssetManifest, DockerImageDestination, DockerImageSource, FileDestination, FileSource, Manifest } from '@aws-cdk/cloud-assembly-schema'; /** * A manifest of assets diff --git a/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts b/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts index 13b1ac7c1dd0c..7fc07f8d30fa5 100644 --- a/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts +++ b/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts @@ -1,9 +1,9 @@ /** * Get access to construct internals that we need but got removed from the Stages PR. */ +import * as path from 'path'; import { App, IConstruct, Stage } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import * as path from 'path'; export function appOf(construct: IConstruct): App { const root = construct.node.root; diff --git a/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts b/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts index 2d5b14470fafc..fc088c46e00a2 100644 --- a/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts +++ b/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts @@ -1,9 +1,9 @@ +import * as path from 'path'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; import * as events from '@aws-cdk/aws-events'; import { Construct } from '@aws-cdk/core'; -import * as path from 'path'; import { cloudAssemblyBuildSpecDir } from '../private/construct-internals'; import { copyEnvironmentVariables, filterEmpty } from './_util'; @@ -54,7 +54,7 @@ export interface SimpleSynthOptions { /** * Build environment to use for CodeBuild job * - * @default BuildEnvironment.LinuxBuildImage.STANDARD_1_0 + * @default BuildEnvironment.LinuxBuildImage.STANDARD_4_0 */ readonly environment?: codebuild.BuildEnvironment; @@ -210,7 +210,7 @@ export class SimpleSynthAction implements codepipeline.IAction { const project = new codebuild.PipelineProject(scope, 'CdkBuildProject', { projectName: this.props.projectName ?? this.props.projectName, - environment: this.props.environment, + environment: { buildImage: codebuild.LinuxBuildImage.STANDARD_4_0, ...this.props.environment }, buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', phases: { diff --git a/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts b/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts index 301e641cb15fa..b5d1d820b8a6b 100644 --- a/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts +++ b/packages/@aws-cdk/pipelines/lib/validation/shell-script-action.ts @@ -134,6 +134,7 @@ export class ShellScriptAction implements codepipeline.IAction { } this._project = new codebuild.PipelineProject(scope, 'Project', { + environment: { buildImage: codebuild.LinuxBuildImage.STANDARD_4_0 }, buildSpec: codebuild.BuildSpec.fromObject({ version: '0.2', phases: { diff --git a/packages/@aws-cdk/pipelines/test/builds.test.ts b/packages/@aws-cdk/pipelines/test/builds.test.ts index 132e46ac28f23..014eb8e79e40f 100644 --- a/packages/@aws-cdk/pipelines/test/builds.test.ts +++ b/packages/@aws-cdk/pipelines/test/builds.test.ts @@ -31,6 +31,9 @@ test.each([['npm'], ['yarn']])('%s build automatically determines artifact base- // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ artifacts: { @@ -55,6 +58,9 @@ test.each([['npm'], ['yarn']])('%s build respects subdirectory', (npmYarn) => { // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { @@ -80,6 +86,9 @@ test.each([['npm'], ['yarn']])('%s assumes no build step by default', (npmYarn) // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { @@ -106,6 +115,9 @@ test.each([['npm'], ['yarn']])('%s can have its install command overridden', (np // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { @@ -141,6 +153,9 @@ test('Standard (NPM) synth can output additional artifacts', () => { // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ artifacts: { diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json index 058eb255d030a..777cffa9703f6 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-assets.expected.json @@ -183,7 +183,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", + "Image": "aws/codebuild/standard:4.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, @@ -1087,7 +1087,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", + "Image": "aws/codebuild/standard:4.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, @@ -1391,7 +1391,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", + "Image": "aws/codebuild/standard:4.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, @@ -1564,7 +1564,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", + "Image": "aws/codebuild/standard:4.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, @@ -1594,7 +1594,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", + "Image": "aws/codebuild/standard:4.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json b/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json index bd0840aeee7ba..7063a7cf29a0d 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline.expected.json @@ -183,7 +183,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", + "Image": "aws/codebuild/standard:4.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, @@ -986,7 +986,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", + "Image": "aws/codebuild/standard:4.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, @@ -1290,7 +1290,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:1.0", + "Image": "aws/codebuild/standard:4.0", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" }, diff --git a/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts b/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts index 41c05e322fa54..25bc092c723ff 100644 --- a/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts +++ b/packages/@aws-cdk/pipelines/test/pipeline-assets.test.ts @@ -41,6 +41,9 @@ test('command line properly locates assets in subassembly', () => { // THEN expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { @@ -107,6 +110,7 @@ test('file image asset publishers do not use privilegedmode, have right AssumeRo }, Environment: objectLike({ PrivilegedMode: false, + Image: 'aws/codebuild/standard:4.0', }), }); @@ -137,6 +141,7 @@ test('docker image asset publishers use privilegedmode, have right AssumeRole', })), }, Environment: objectLike({ + Image: 'aws/codebuild/standard:4.0', PrivilegedMode: true, }), }); @@ -161,6 +166,9 @@ test('can control fix/CLI version used in pipeline selfupdate', () => { // THEN expect(stack2).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { diff --git a/packages/@aws-cdk/pipelines/test/pipeline.test.ts b/packages/@aws-cdk/pipelines/test/pipeline.test.ts index 08567b3741961..421075cc2b02b 100644 --- a/packages/@aws-cdk/pipelines/test/pipeline.test.ts +++ b/packages/@aws-cdk/pipelines/test/pipeline.test.ts @@ -177,6 +177,9 @@ test('pipeline has self-mutation stage', () => { }); expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { @@ -200,6 +203,9 @@ test('selfmutation stage correctly identifies nested assembly of pipeline stack' // THEN expect(stackTemplate(nestedPipelineStack)).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { diff --git a/packages/@aws-cdk/pipelines/test/testutil.ts b/packages/@aws-cdk/pipelines/test/testutil.ts index 9c87e64c502b7..ca5cb3db0e672 100644 --- a/packages/@aws-cdk/pipelines/test/testutil.ts +++ b/packages/@aws-cdk/pipelines/test/testutil.ts @@ -1,9 +1,9 @@ +import * as fs from 'fs'; +import * as path from 'path'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; import * as s3 from '@aws-cdk/aws-s3'; import { App, AppProps, Construct, Environment, SecretValue, Stack, StackProps, Stage } from '@aws-cdk/core'; -import * as fs from 'fs'; -import * as path from 'path'; import * as cdkp from '../lib'; import { assemblyBuilderOf } from '../lib/private/construct-internals'; diff --git a/packages/@aws-cdk/pipelines/test/validation.test.ts b/packages/@aws-cdk/pipelines/test/validation.test.ts index dffe91ebe4dfd..2e57aaa30c0fc 100644 --- a/packages/@aws-cdk/pipelines/test/validation.test.ts +++ b/packages/@aws-cdk/pipelines/test/validation.test.ts @@ -75,6 +75,9 @@ test('can use stack outputs as validation inputs', () => { }); expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { @@ -113,6 +116,9 @@ test('can use additional files from source', () => { }), }); expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { @@ -149,6 +155,9 @@ test('can use additional files from build', () => { }), }); expect(pipelineStack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + Image: 'aws/codebuild/standard:4.0', + }, Source: { BuildSpec: encodedJson(deepObjectLike({ phases: { From aa4c5b7df3a4880638361026ec0f6a77b7476b40 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 10 Aug 2020 17:02:43 +0300 Subject: [PATCH 12/43] feat(core): deprecate "Construct.node" in favor of "Construct.construct" (#9557) To reduce the chance for conflicts with generated domain-specific properties in subclasses of `Construct` (see [terraform-cdk issue]), we decided that we will rename `node` to `construct`, which is less prevalent. We plan to remove the `node` API in the next major version of the AWS CDK, and therefore recommend users to migrate their code to use `construct` instead. See discussion in the [RFC]. [terraform-cdk issue]: https://github.com/hashicorp/terraform-cdk/pull/230 [RFC]: https://github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#10-construct-node ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../integ.load-balanced-fargate-service.ts | 10 +- .../test.load-balanced-fargate-service.ts | 15 +- .../@aws-cdk/aws-lambda/lib/function-base.ts | 1 + .../@aws-cdk/aws-route53/test/test.util.ts | 4 + packages/@aws-cdk/core/README.md | 10 +- packages/@aws-cdk/core/lib/app.ts | 8 +- packages/@aws-cdk/core/lib/asset-staging.ts | 8 +- packages/@aws-cdk/core/lib/cfn-element.ts | 6 +- packages/@aws-cdk/core/lib/cfn-output.ts | 2 +- packages/@aws-cdk/core/lib/cfn-parse.ts | 2 +- packages/@aws-cdk/core/lib/cfn-resource.ts | 10 +- .../@aws-cdk/core/lib/construct-compat.ts | 23 +- .../@aws-cdk/core/lib/context-provider.ts | 4 +- .../custom-resource-provider.ts | 2 +- packages/@aws-cdk/core/lib/deps.ts | 6 +- packages/@aws-cdk/core/lib/nested-stack.ts | 4 +- .../core/lib/private/cfn-reference.ts | 7 +- .../lib/private/physical-name-generator.ts | 6 +- .../@aws-cdk/core/lib/private/prepare-app.ts | 6 +- packages/@aws-cdk/core/lib/private/refs.ts | 22 +- .../@aws-cdk/core/lib/private/synthesis.ts | 12 +- .../core/lib/private/tree-metadata.ts | 10 +- packages/@aws-cdk/core/lib/resource.ts | 2 +- .../core/lib/stack-synthesizers/_shared.ts | 12 +- .../stack-synthesizers/default-synthesizer.ts | 2 +- .../core/lib/stack-synthesizers/legacy.ts | 8 +- packages/@aws-cdk/core/lib/stack.ts | 34 +-- packages/@aws-cdk/core/lib/stage.ts | 10 +- .../test.custom-resource-provider.ts | 2 +- .../core/test/private/test.tree-metadata.ts | 4 +- packages/@aws-cdk/core/test/test.app.ts | 32 +-- packages/@aws-cdk/core/test/test.aspect.ts | 22 +- packages/@aws-cdk/core/test/test.assets.ts | 10 +- .../@aws-cdk/core/test/test.cfn-resource.ts | 2 +- packages/@aws-cdk/core/test/test.construct.ts | 208 +++++++++--------- packages/@aws-cdk/core/test/test.context.ts | 8 +- .../@aws-cdk/core/test/test.logical-id.ts | 6 +- packages/@aws-cdk/core/test/test.resource.ts | 14 +- packages/@aws-cdk/core/test/test.stack.ts | 10 +- packages/@aws-cdk/core/test/test.stage.ts | 6 +- packages/@aws-cdk/core/test/test.staging.ts | 2 +- packages/@aws-cdk/core/test/test.synthesis.ts | 2 +- packages/@aws-cdk/core/test/test.util.ts | 4 +- 43 files changed, 293 insertions(+), 285 deletions(-) diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.ts index f4ecc0f0a5616..9e0ac7a1e2403 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.ts @@ -1,6 +1,7 @@ import { Vpc } from '@aws-cdk/aws-ec2'; import { Cluster, ContainerImage } from '@aws-cdk/aws-ecs'; import { ApplicationProtocol } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { HostedZone } from '@aws-cdk/aws-route53'; import { App, Stack } from '@aws-cdk/core'; import { ApplicationLoadBalancedFargateService } from '../../lib'; @@ -20,13 +21,10 @@ new ApplicationLoadBalancedFargateService(stack, 'myService', { protocol: ApplicationProtocol.HTTPS, enableECSManagedTags: true, domainName: 'test.example.com', - domainZone: { + domainZone: HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { hostedZoneId: 'fakeId', - zoneName: 'example.com.', - hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', - stack, - node: stack.node, - }, + zoneName: 'example.com', + }), }); app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts index 4b30dfa721480..aed0414695b64 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts @@ -3,6 +3,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; import * as iam from '@aws-cdk/aws-iam'; +import * as route53 from '@aws-cdk/aws-route53'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as ecsPatterns from '../../lib'; @@ -370,13 +371,10 @@ export = { cluster, protocol: ApplicationProtocol.HTTPS, domainName: 'domain.com', - domainZone: { + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'MyHostedZone', { hostedZoneId: 'fakeId', zoneName: 'domain.com', - hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', - stack, - node: stack.node, - }, + }), taskImageOptions: { containerPort: 2015, image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), @@ -408,13 +406,10 @@ export = { cluster, protocol: ApplicationProtocol.HTTPS, domainName: 'test.domain.com', - domainZone: { + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'MyHostedZone', { hostedZoneId: 'fakeId', zoneName: 'domain.com.', - hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', - stack, - node: stack.node, - }, + }), taskImageOptions: { containerPort: 2015, image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index 39ad7d665fcb7..31f6eeab09f3f 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -287,6 +287,7 @@ export abstract class FunctionBase extends Resource implements IFunction { return { statementAdded: true, policyDependable: this._functionNode().findChild(identifier) } as iam.AddToResourcePolicyResult; }, node: this.node, + construct: this.construct, }, }); } diff --git a/packages/@aws-cdk/aws-route53/test/test.util.ts b/packages/@aws-cdk/aws-route53/test/test.util.ts index 006527d3ad869..6afb828aae570 100644 --- a/packages/@aws-cdk/aws-route53/test/test.util.ts +++ b/packages/@aws-cdk/aws-route53/test/test.util.ts @@ -26,6 +26,7 @@ export = { hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', stack, node: stack.node, + construct: stack.construct, }); // THEN @@ -45,6 +46,7 @@ export = { hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', stack, node: stack.node, + construct: stack.construct, }); // THEN @@ -64,6 +66,7 @@ export = { hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', stack, node: stack.node, + construct: stack.construct, }); // THEN @@ -83,6 +86,7 @@ export = { hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', stack, node: stack.node, + construct: stack.construct, }); // THEN diff --git a/packages/@aws-cdk/core/README.md b/packages/@aws-cdk/core/README.md index d2a240166995c..d6a5d9a902032 100644 --- a/packages/@aws-cdk/core/README.md +++ b/packages/@aws-cdk/core/README.md @@ -214,7 +214,7 @@ you. If you need to add an ordering dependency that is not automatically inferred, you do so by adding a dependency relationship using -`constructA.node.addDependency(constructB)`. This will add a dependency +`constructA.construct.addDependency(constructB)`. This will add a dependency relationship between all resources in the scope of `constructA` and all resources in the scope of `constructB`. @@ -230,7 +230,7 @@ bAndC.add(constructB); bAndC.add(constructC); // Take the dependency -constructA.node.addDependency(bAndC); +constructA.construct.addDependency(bAndC); ``` ### Stack Dependencies @@ -319,7 +319,7 @@ examples ensures that only a single SNS topic is defined: function getOrCreate(scope: Construct): sns.Topic { const stack = Stack.of(this); const uniqueid = 'GloballyUniqueIdForSingleton'; - return stack.node.tryFindChild(uniqueid) as sns.Topic ?? new sns.Topic(stack, uniqueid); + return stack.construct.tryFindChild(uniqueid) as sns.Topic ?? new sns.Topic(stack, uniqueid); } ``` @@ -675,7 +675,7 @@ accessing those through the `cfnOptions` property: ```ts const rawBucket = new s3.CfnBucket(this, 'Bucket', { /* ... */ }); // -or- -const rawBucket = bucket.node.defaultChild as s3.CfnBucket; +const rawBucket = bucket.construct.defaultChild as s3.CfnBucket; // then rawBucket.cfnOptions.condition = new CfnCondition(this, 'EnableBucket', { /* ... */ }); @@ -734,7 +734,7 @@ const stage = Fn.conditionIf(isProd.logicalId, 'Beta', 'Prod').toString(); // Make Bucket creation condition to IsProduction by accessing // and overriding the CloudFormation resource const bucket = new s3.Bucket(this, 'Bucket'); -const cfnBucket = bucket.node.defaultChild as s3.CfnBucket; +const cfnBucket = bucket.construct.defaultChild as s3.CfnBucket; cfnBucket.cfnOptions.condition = isProd; ``` diff --git a/packages/@aws-cdk/core/lib/app.ts b/packages/@aws-cdk/core/lib/app.ts index 50996a72ff85a..ba87fe7a86197 100644 --- a/packages/@aws-cdk/core/lib/app.ts +++ b/packages/@aws-cdk/core/lib/app.ts @@ -98,11 +98,11 @@ export class App extends Stage { this.loadContext(props.context); if (props.stackTraces === false) { - this.node.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true); + this.construct.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true); } if (props.runtimeInfo === false) { - this.node.setContext(cxapi.DISABLE_VERSION_REPORTING, true); + this.construct.setContext(cxapi.DISABLE_VERSION_REPORTING, true); } const autoSynth = props.autoSynth !== undefined ? props.autoSynth : cxapi.OUTDIR_ENV in process.env; @@ -120,7 +120,7 @@ export class App extends Stage { private loadContext(defaults: { [key: string]: string } = { }) { // prime with defaults passed through constructor for (const [ k, v ] of Object.entries(defaults)) { - this.node.setContext(k, v); + this.construct.setContext(k, v); } // read from environment @@ -130,7 +130,7 @@ export class App extends Stage { : { }; for (const [ k, v ] of Object.entries(contextFromEnvironment)) { - this.node.setContext(k, v); + this.construct.setContext(k, v); } } } diff --git a/packages/@aws-cdk/core/lib/asset-staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts index c42cf35f2b5a8..0d1c9ecad7c39 100644 --- a/packages/@aws-cdk/core/lib/asset-staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -5,9 +5,9 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as fs from 'fs-extra'; import { AssetHashType, AssetOptions } from './assets'; import { BundlingOptions } from './bundling'; +import { Construct } from './construct-compat'; import { FileSystem, FingerprintOptions } from './fs'; import { Stage } from './stage'; -import { Construct } from './construct-compat'; const STAGING_TMP = '.cdk.staging'; @@ -95,7 +95,7 @@ export class AssetStaging extends Construct { this.assetHash = this.calculateHash(props); - const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT); + const stagingDisabled = this.construct.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT); if (stagingDisabled) { this.stagedPath = this.bundleDir ?? this.sourcePath; } else { @@ -179,7 +179,7 @@ export class AssetStaging extends Construct { ]; try { - process.stderr.write(`Bundling asset ${this.node.path}...\n`); + process.stderr.write(`Bundling asset ${this.construct.path}...\n`); options.image._run({ command: options.command, user, @@ -188,7 +188,7 @@ export class AssetStaging extends Construct { workingDirectory: options.workingDirectory ?? AssetStaging.BUNDLING_INPUT_DIR, }); } catch (err) { - throw new Error(`Failed to run bundling Docker image for asset ${this.node.path}: ${err}`); + throw new Error(`Failed to run bundling Docker image for asset ${this.construct.path}: ${err}`); } if (FileSystem.isEmpty(bundleDir)) { diff --git a/packages/@aws-cdk/core/lib/cfn-element.ts b/packages/@aws-cdk/core/lib/cfn-element.ts index 7aadf278f13cd..2e6562b247f79 100644 --- a/packages/@aws-cdk/core/lib/cfn-element.ts +++ b/packages/@aws-cdk/core/lib/cfn-element.ts @@ -58,10 +58,10 @@ export abstract class CfnElement extends Construct { this.stack = Stack.of(this); this.logicalId = Lazy.stringValue({ produce: () => this.synthesizeLogicalId() }, { - displayHint: `${notTooLong(this.node.path)}.LogicalID`, + displayHint: `${notTooLong(this.construct.path)}.LogicalID`, }); - this.node.addMetadata(cxschema.ArtifactMetadataEntryType.LOGICAL_ID, this.logicalId, this.constructor); + this.construct.addMetadata(cxschema.ArtifactMetadataEntryType.LOGICAL_ID, this.logicalId, this.constructor); } /** @@ -78,7 +78,7 @@ export abstract class CfnElement extends Construct { * node +internal+ entries filtered. */ public get creationStack(): string[] { - const trace = this.node.metadata.find(md => md.type === cxschema.ArtifactMetadataEntryType.LOGICAL_ID)!.trace; + const trace = this.construct.metadata.find(md => md.type === cxschema.ArtifactMetadataEntryType.LOGICAL_ID)!.trace; if (!trace) { return []; } diff --git a/packages/@aws-cdk/core/lib/cfn-output.ts b/packages/@aws-cdk/core/lib/cfn-output.ts index 3f2784f890073..4714f3d99cf3d 100644 --- a/packages/@aws-cdk/core/lib/cfn-output.ts +++ b/packages/@aws-cdk/core/lib/cfn-output.ts @@ -50,7 +50,7 @@ export class CfnOutput extends CfnElement { super(scope, id); if (props.value === undefined) { - throw new Error(`Missing value for CloudFormation output at path "${this.node.path}"`); + throw new Error(`Missing value for CloudFormation output at path "${this.construct.path}"`); } this._description = props.description; diff --git a/packages/@aws-cdk/core/lib/cfn-parse.ts b/packages/@aws-cdk/core/lib/cfn-parse.ts index 5872399e0efee..a58e54f097be4 100644 --- a/packages/@aws-cdk/core/lib/cfn-parse.ts +++ b/packages/@aws-cdk/core/lib/cfn-parse.ts @@ -221,7 +221,7 @@ export class CfnParser { if (!depResource) { throw new Error(`Resource '${logicalId}' depends on '${dep}' that doesn't exist`); } - resource.node.addDependency(depResource); + resource.construct.addDependency(depResource); } } diff --git a/packages/@aws-cdk/core/lib/cfn-resource.ts b/packages/@aws-cdk/core/lib/cfn-resource.ts index 9af3aa5c16a21..45ad083e5591d 100644 --- a/packages/@aws-cdk/core/lib/cfn-resource.ts +++ b/packages/@aws-cdk/core/lib/cfn-resource.ts @@ -92,8 +92,8 @@ export class CfnResource extends CfnRefElement { // if aws:cdk:enable-path-metadata is set, embed the current construct's // path in the CloudFormation template, so it will be possible to trace // back to the actual construct path. - if (this.node.tryGetContext(cxapi.PATH_METADATA_ENABLE_CONTEXT)) { - this.addMetadata(cxapi.PATH_METADATA_KEY, this.node.path); + if (this.construct.tryGetContext(cxapi.PATH_METADATA_ENABLE_CONTEXT)) { + this.addMetadata(cxapi.PATH_METADATA_KEY, this.construct.path); } } @@ -238,7 +238,7 @@ export class CfnResource extends CfnRefElement { return; } - addDependency(this, target, `"${this.node.path}" depends on "${target.node.path}"`); + addDependency(this, target, `"${this.construct.path}" depends on "${target.construct.path}"`); } /** @@ -312,7 +312,7 @@ export class CfnResource extends CfnRefElement { return ret; } catch (e) { // Change message - e.message = `While synthesizing ${this.node.path}: ${e.message}`; + e.message = `While synthesizing ${this.construct.path}: ${e.message}`; // Adjust stack trace (make it look like node built it, too...) const trace = this.creationStack; if (trace) { @@ -330,7 +330,7 @@ export class CfnResource extends CfnRefElement { function renderDependsOn(dependsOn: Set) { return Array .from(dependsOn) - .sort((x, y) => x.node.path.localeCompare(y.node.path)) + .sort((x, y) => x.construct.path.localeCompare(y.construct.path)) .map(r => r.logicalId); } diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index 315fa8a38232f..57a7269906b57 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -28,6 +28,11 @@ export interface IConstruct extends constructs.IConstruct, IDependable { * The construct tree node for this construct. */ readonly node: ConstructNode; + + /** + * The construct tree node for this construct. + */ + readonly construct: ConstructNode; } /** @@ -61,9 +66,18 @@ export class Construct extends constructs.Construct implements IConstruct { /** * The construct tree node associated with this construct. + * + * @deprecate `Construct.node` is being deprecated in favor of + * `Construct.construct`. This API will be removed in the next major version + * of the AWS CDK, please migrate your code to use `construct` instead. */ public readonly node: ConstructNode; + /** + * Construct API. + */ + public readonly construct: ConstructNode; + constructor(scope: Construct, id: string) { super(scope, id, { nodeFactory: { @@ -78,15 +92,16 @@ export class Construct extends constructs.Construct implements IConstruct { Object.defineProperty(this, CONSTRUCT_SYMBOL, { value: true }); this.node = ConstructNode._unwrap(constructs.Node.of(this)); + this.construct = this.node; const disableTrace = - this.node.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) || - this.node.tryGetContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA) || + this.construct.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) || + this.construct.tryGetContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA) || process.env.CDK_DISABLE_STACK_TRACE; if (disableTrace) { - this.node.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true); - this.node.setContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA, true); + this.construct.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true); + this.construct.setContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA, true); process.env.CDK_DISABLE_STACK_TRACE = '1'; } } diff --git a/packages/@aws-cdk/core/lib/context-provider.ts b/packages/@aws-cdk/core/lib/context-provider.ts index d5c7928649f37..8f0e968416c28 100644 --- a/packages/@aws-cdk/core/lib/context-provider.ts +++ b/packages/@aws-cdk/core/lib/context-provider.ts @@ -94,7 +94,7 @@ export class ContextProvider { } const { key, props } = this.getKey(scope, options); - const value = scope.node.tryGetContext(key); + const value = scope.construct.tryGetContext(key); const providerError = extractProviderError(value); // if context is missing or an error occurred during context retrieval, @@ -107,7 +107,7 @@ export class ContextProvider { }); if (providerError !== undefined) { - scope.node.addError(providerError); + scope.construct.addError(providerError); } return { value: options.dummyValue }; } diff --git a/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts b/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts index 8b24d068235f9..21decaf371076 100644 --- a/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts +++ b/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts @@ -91,7 +91,7 @@ export class CustomResourceProvider extends Construct { public static getOrCreate(scope: Construct, uniqueid: string, props: CustomResourceProviderProps) { const id = `${uniqueid}CustomResourceProvider`; const stack = Stack.of(scope); - const provider = stack.node.tryFindChild(id) as CustomResourceProvider + const provider = stack.construct.tryFindChild(id) as CustomResourceProvider ?? new CustomResourceProvider(stack, id, props); return provider.serviceToken; diff --git a/packages/@aws-cdk/core/lib/deps.ts b/packages/@aws-cdk/core/lib/deps.ts index e0ef970b6e359..55726d7dac46e 100644 --- a/packages/@aws-cdk/core/lib/deps.ts +++ b/packages/@aws-cdk/core/lib/deps.ts @@ -36,7 +36,7 @@ export function addDependency(source: T, target: T, reason?: const targetStage = Stage.of(targetStack); if (sourceStage !== targetStage) { // eslint-disable-next-line max-len - throw new Error(`You cannot add a dependency from '${source.node.path}' (in ${describeStage(sourceStage)}) to '${target.node.path}' (in ${describeStage(targetStage)}): dependency cannot cross stage boundaries`); + throw new Error(`You cannot add a dependency from '${source.construct.path}' (in ${describeStage(sourceStage)}) to '${target.construct.path}' (in ${describeStage(targetStage)}): dependency cannot cross stage boundaries`); } // find the deepest common stack between the two elements @@ -70,7 +70,7 @@ export function addDependency(source: T, target: T, reason?: // `source` is a direct or indirect nested stack of `target`, and this is not // possible (nested stacks cannot depend on their parents). if (commonStack === target) { - throw new Error(`Nested stack '${sourceStack.node.path}' cannot depend on a parent stack '${targetStack.node.path}': ${reason}`); + throw new Error(`Nested stack '${sourceStack.construct.path}' cannot depend on a parent stack '${targetStack.construct.path}': ${reason}`); } // we have a common stack from which we can reach both `source` and `target` @@ -103,5 +103,5 @@ export function addDependency(source: T, target: T, reason?: function describeStage(assembly: Stage | undefined): string { if (!assembly) { return 'an unrooted construct tree'; } if (!assembly.parentStage) { return 'the App'; } - return `Stage '${assembly.node.path}'`; + return `Stage '${assembly.construct.path}'`; } diff --git a/packages/@aws-cdk/core/lib/nested-stack.ts b/packages/@aws-cdk/core/lib/nested-stack.ts index 7e52427467039..cd9e6be048d44 100644 --- a/packages/@aws-cdk/core/lib/nested-stack.ts +++ b/packages/@aws-cdk/core/lib/nested-stack.ts @@ -110,7 +110,7 @@ export class NestedStack extends Stack { Object.defineProperty(this, NESTED_STACK_SYMBOL, { value: true }); // this is the file name of the synthesized template file within the cloud assembly - this.templateFile = `${this.node.uniqueId}.nested.template.json`; + this.templateFile = `${this.construct.uniqueId}.nested.template.json`; this.parameters = props.parameters || {}; @@ -223,7 +223,7 @@ function findParentStack(scope: Construct): Stack { throw new Error('Nested stacks cannot be defined as a root construct'); } - const parentStack = scope.node.scopes.reverse().find(p => Stack.isStack(p)); + const parentStack = scope.construct.scopes.reverse().find(p => Stack.isStack(p)); if (!parentStack) { throw new Error('Nested stacks must be defined within scope of another non-nested stack'); } diff --git a/packages/@aws-cdk/core/lib/private/cfn-reference.ts b/packages/@aws-cdk/core/lib/private/cfn-reference.ts index 491232e344840..a20457d7f6e6d 100644 --- a/packages/@aws-cdk/core/lib/private/cfn-reference.ts +++ b/packages/@aws-cdk/core/lib/private/cfn-reference.ts @@ -102,11 +102,6 @@ export class CfnReference extends Reference { const consumingStack = Stack.of(context.scope); const token = this.replacementTokens.get(consumingStack); - // if (!token && this.isCrossStackReference(consumingStack) && !context.preparing) { - // eslint-disable-next-line max-len - // throw new Error(`Cross-stack reference (${context.scope.node.path} -> ${this.target.node.path}) has not been assigned a value--call prepare() first`); - // } - if (token) { return token.resolve(context); } else { @@ -138,7 +133,7 @@ export class CfnReference extends Reference { */ public toString(): string { return Token.asString(this, { - displayHint: `${this.target.node.id}.${this.displayName}`, + displayHint: `${this.target.construct.id}.${this.displayName}`, }); } } diff --git a/packages/@aws-cdk/core/lib/private/physical-name-generator.ts b/packages/@aws-cdk/core/lib/private/physical-name-generator.ts index dbd0a2c8af772..993c63c1db211 100644 --- a/packages/@aws-cdk/core/lib/private/physical-name-generator.ts +++ b/packages/@aws-cdk/core/lib/private/physical-name-generator.ts @@ -8,16 +8,16 @@ import { TokenMap } from './token-map'; export function generatePhysicalName(resource: IResource): string { const stack = Stack.of(resource); const stackPart = new PrefixNamePart(stack.stackName, 25); - const idPart = new SuffixNamePart(resource.node.uniqueId, 24); + const idPart = new SuffixNamePart(resource.construct.uniqueId, 24); const region: string = stack.region; if (Token.isUnresolved(region) || !region) { - throw new Error(`Cannot generate a physical name for ${resource.node.path}, because the region is un-resolved or missing`); + throw new Error(`Cannot generate a physical name for ${resource.construct.path}, because the region is un-resolved or missing`); } const account: string = stack.account; if (Token.isUnresolved(account) || !account) { - throw new Error(`Cannot generate a physical name for ${resource.node.path}, because the account is un-resolved or missing`); + throw new Error(`Cannot generate a physical name for ${resource.construct.path}, because the account is un-resolved or missing`); } const parts = [stackPart, idPart] diff --git a/packages/@aws-cdk/core/lib/private/prepare-app.ts b/packages/@aws-cdk/core/lib/private/prepare-app.ts index ad900acf803c0..a8d1d33ed04d1 100644 --- a/packages/@aws-cdk/core/lib/private/prepare-app.ts +++ b/packages/@aws-cdk/core/lib/private/prepare-app.ts @@ -17,7 +17,7 @@ import { resolveReferences } from './refs'; */ export function prepareApp(root: IConstruct) { // apply dependencies between resources in depending subtrees - for (const dependency of root.node.dependencies) { + for (const dependency of root.construct.dependencies) { const targetCfnResources = findCfnResources(dependency.target); const sourceCfnResources = findCfnResources(dependency.source); @@ -71,7 +71,7 @@ function findAllNestedStacks(root: IConstruct) { // create a list of all nested stacks in depth-first post order this means // that we first prepare the leaves and then work our way up. - for (const stack of root.node.findAll(ConstructOrder.POSTORDER /* <== important */)) { + for (const stack of root.construct.findAll(ConstructOrder.POSTORDER /* <== important */)) { if (includeStack(stack)) { result.push(stack); } @@ -84,7 +84,7 @@ function findAllNestedStacks(root: IConstruct) { * Find all resources in a set of constructs */ function findCfnResources(root: IConstruct): CfnResource[] { - return root.node.findAll().filter(CfnResource.isCfnResource); + return root.construct.findAll().filter(CfnResource.isCfnResource); } interface INestedStackPrivateApi { diff --git a/packages/@aws-cdk/core/lib/private/refs.ts b/packages/@aws-cdk/core/lib/private/refs.ts index 62a568f8cd736..cfe56226aa130 100644 --- a/packages/@aws-cdk/core/lib/private/refs.ts +++ b/packages/@aws-cdk/core/lib/private/refs.ts @@ -44,14 +44,14 @@ function resolveValue(consumer: Stack, reference: CfnReference): IResolvable { } // unsupported: stacks from different apps - if (producer.node.root !== consumer.node.root) { + if (producer.construct.root !== consumer.construct.root) { throw new Error('Cannot reference across apps. Consuming and producing stacks must be defined within the same CDK app.'); } // unsupported: stacks are not in the same environment if (producer.environment !== consumer.environment) { throw new Error( - `Stack "${consumer.node.path}" cannot consume a cross reference from stack "${producer.node.path}". ` + + `Stack "${consumer.construct.path}" cannot consume a cross reference from stack "${producer.construct.path}". ` + 'Cross stack references are only supported for stacks deployed to the same environment or between nested stacks and their parent stack'); } @@ -97,7 +97,7 @@ function resolveValue(consumer: Stack, reference: CfnReference): IResolvable { // will take care of applying the dependency at the right level (e.g. the // top-level stacks). consumer.addDependency(producer, - `${consumer.node.path} -> ${reference.target.node.path}.${reference.displayName}`); + `${consumer.construct.path} -> ${reference.target.construct.path}.${reference.displayName}`); return createImportValue(reference); } @@ -107,7 +107,7 @@ function resolveValue(consumer: Stack, reference: CfnReference): IResolvable { */ function findAllReferences(root: IConstruct) { const result = new Array<{ source: CfnElement, value: CfnReference }>(); - for (const consumer of root.node.findAll()) { + for (const consumer of root.construct.findAll()) { // include only CfnElements (i.e. resources) if (!CfnElement.isCfnElement(consumer)) { @@ -178,7 +178,7 @@ function createImportValue(reference: Reference): Intrinsic { throw new Error(`unresolved token in generated export name: ${JSON.stringify(exportingStack.resolve(exportName))}`); } - const output = exportsScope.node.tryFindChild(id) as CfnOutput; + const output = exportsScope.construct.tryFindChild(id) as CfnOutput; if (!output) { new CfnOutput(exportsScope, id, { value: Token.asString(reference), exportName }); } @@ -190,7 +190,7 @@ function createImportValue(reference: Reference): Intrinsic { function getCreateExportsScope(stack: Stack) { const exportsName = 'Exports'; - let stackExports = stack.node.tryFindChild(exportsName) as Construct; + let stackExports = stack.construct.tryFindChild(exportsName) as Construct; if (stackExports === undefined) { stackExports = new Construct(stack, exportsName); } @@ -200,7 +200,7 @@ function getCreateExportsScope(stack: Stack) { function generateExportName(stackExports: Construct, id: string) { const stack = Stack.of(stackExports); - const components = [...stackExports.node.scopes.slice(2).map(c => c.node.id), id]; + const components = [...stackExports.construct.scopes.slice(2).map(c => c.construct.id), id]; const prefix = stack.stackName ? stack.stackName + ':' : ''; const exportName = prefix + makeUniqueId(components); return exportName; @@ -216,8 +216,8 @@ function generateExportName(stackExports: Construct, id: string) { */ function createNestedStackParameter(nested: Stack, reference: CfnReference, value: IResolvable) { // we call "this.resolve" to ensure that tokens do not creep in (for example, if the reference display name includes tokens) - const paramId = nested.resolve(`reference-to-${reference.target.node.uniqueId}.${reference.displayName}`); - let param = nested.node.tryFindChild(paramId) as CfnParameter; + const paramId = nested.resolve(`reference-to-${reference.target.construct.uniqueId}.${reference.displayName}`); + let param = nested.construct.tryFindChild(paramId) as CfnParameter; if (!param) { param = new CfnParameter(nested, paramId, { type: 'String' }); @@ -237,8 +237,8 @@ function createNestedStackParameter(nested: Stack, reference: CfnReference, valu * intrinsic that can be used to reference this output in the parent stack. */ function createNestedStackOutput(producer: Stack, reference: Reference): CfnReference { - const outputId = `${reference.target.node.uniqueId}${reference.displayName}`; - let output = producer.node.tryFindChild(outputId) as CfnOutput; + const outputId = `${reference.target.construct.uniqueId}${reference.displayName}`; + let output = producer.construct.tryFindChild(outputId) as CfnOutput; if (!output) { output = new CfnOutput(producer, outputId, { value: Token.asString(reference) }); } diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index 77f0bacb7004a..537c2fa3ac5ee 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -45,7 +45,7 @@ export function synthesize(root: IConstruct, options: SynthesisOptions = { }): c * (They will in turn recurse again) */ function synthNestedAssemblies(root: IConstruct, options: StageSynthesisOptions) { - for (const child of root.node.children) { + for (const child of root.construct.children) { if (Stage.isStage(child)) { child.synth(options); } else { @@ -67,7 +67,7 @@ function invokeAspects(root: IConstruct) { recurse(root, []); function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) { - const node = construct.node; + const node = construct.construct; const aspects = Aspects.of(construct); const allAspectsHere = [...inheritedAspects ?? [], ...aspects.aspects]; const nodeAspectsCount = aspects.aspects.length; @@ -84,7 +84,7 @@ function invokeAspects(root: IConstruct) { // if an aspect was added to the node while invoking another aspect it will not be invoked, emit a warning // the `nestedAspectWarning` flag is used to prevent the warning from being emitted for every child if (!nestedAspectWarning && nodeAspectsCount !== aspects.aspects.length) { - construct.node.addWarning('We detected an Aspect was added via another Aspect, and will not be applied'); + construct.construct.addWarning('We detected an Aspect was added via another Aspect, and will not be applied'); nestedAspectWarning = true; } @@ -92,7 +92,7 @@ function invokeAspects(root: IConstruct) { invoked.push(aspect); } - for (const child of construct.node.children) { + for (const child of construct.construct.children) { if (!Stage.isStage(child)) { recurse(child, allAspectsHere); } @@ -146,7 +146,7 @@ function validateTree(root: IConstruct) { }); if (errors.length > 0) { - const errorList = errors.map(e => `[${e.source.node.path}] ${e.message}`).join('\n '); + const errorList = errors.map(e => `[${e.source.construct.path}] ${e.message}`).join('\n '); throw new Error(`Validation failed with the following errors:\n ${errorList}`); } } @@ -159,7 +159,7 @@ function visit(root: IConstruct, order: 'pre' | 'post', cb: (x: IProtectedConstr cb(root as IProtectedConstructMethods); } - for (const child of root.node.children) { + for (const child of root.construct.children) { if (Stage.isStage(child)) { continue; } visit(child, order, cb); } diff --git a/packages/@aws-cdk/core/lib/private/tree-metadata.ts b/packages/@aws-cdk/core/lib/private/tree-metadata.ts index b2f288d97b4b4..018179c0a1388 100644 --- a/packages/@aws-cdk/core/lib/private/tree-metadata.ts +++ b/packages/@aws-cdk/core/lib/private/tree-metadata.ts @@ -28,11 +28,11 @@ export class TreeMetadata extends Construct { const lookup: { [path: string]: Node } = { }; const visit = (construct: IConstruct): Node => { - const children = construct.node.children.map((c) => { + const children = construct.construct.children.map((c) => { try { return visit(c); } catch (e) { - this.node.addWarning(`Failed to render tree metadata for node [${c.node.id}]. Reason: ${e}`); + this.construct.addWarning(`Failed to render tree metadata for node [${c.construct.id}]. Reason: ${e}`); return undefined; } }); @@ -41,8 +41,8 @@ export class TreeMetadata extends Construct { .reduce((map, child) => Object.assign(map, { [child!.id]: child }), {}); const node: Node = { - id: construct.node.id || 'App', - path: construct.node.path, + id: construct.construct.id || 'App', + path: construct.construct.path, children: Object.keys(childrenMap).length === 0 ? undefined : childrenMap, attributes: this.synthAttributes(construct), }; @@ -54,7 +54,7 @@ export class TreeMetadata extends Construct { const tree = { version: 'tree-0.1', - tree: visit(this.node.root), + tree: visit(this.construct.root), }; const builder = session.assembly; diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index 6574dbe331da0..129deed73d04f 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -96,7 +96,7 @@ export abstract class Resource extends Construct implements IResource { public _enableCrossEnvironment(): void { if (!this._allowCrossEnvironment) { // error out - a deploy-time name cannot be used across environments - throw new Error(`Cannot use resource '${this.node.path}' in a cross-environment fashion, ` + + throw new Error(`Cannot use resource '${this.construct.path}' in a cross-environment fashion, ` + "the resource's physical name must be explicit set or use `PhysicalName.GENERATE_IF_NEEDED`"); } diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts index 5a57c423779df..29a139020c1b2 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts @@ -23,7 +23,7 @@ export function addStackArtifactToAssembly( // level and are not needed in the cloud assembly. // TODO: move these to the cloud assembly artifact properties instead of metadata if (stack.tags.hasTags()) { - stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, stack.tags.renderTags()); + stack.construct.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, stack.tags.renderTags()); } const deps = [ @@ -77,12 +77,12 @@ function collectStackMetadata(stack: Stack) { return; } - if (node.node.metadata.length > 0) { + if (node.construct.metadata.length > 0) { // Make the path absolute - output[ConstructNode.PATH_SEP + node.node.path] = node.node.metadata.map(md => stack.resolve(md) as cxschema.MetadataEntry); + output[ConstructNode.PATH_SEP + node.construct.path] = node.construct.metadata.map(md => stack.resolve(md) as cxschema.MetadataEntry); } - for (const child of node.node.children) { + for (const child of node.construct.children) { visit(child); } } @@ -92,11 +92,11 @@ function collectStackMetadata(stack: Stack) { return node; } - if (!node.node.scope) { + if (!node.construct.scope) { return undefined; } - return findParentStack(node.node.scope); + return findParentStack(node.construct.scope); } } diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts index 5a373cd3ed061..dd873b6d13e6a 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts @@ -207,7 +207,7 @@ export class DefaultStackSynthesizer implements IStackSynthesizer { public bind(stack: Stack): void { this._stack = stack; - const qualifier = this.props.qualifier ?? stack.node.tryGetContext(BOOTSTRAP_QUALIFIER_CONTEXT) ?? DefaultStackSynthesizer.DEFAULT_QUALIFIER; + const qualifier = this.props.qualifier ?? stack.construct.tryGetContext(BOOTSTRAP_QUALIFIER_CONTEXT) ?? DefaultStackSynthesizer.DEFAULT_QUALIFIER; // Function to replace placeholders in the input string as much as possible // diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts index 06facd881626f..850d1f08d2135 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts @@ -102,7 +102,7 @@ export class LegacyStackSynthesizer implements IStackSynthesizer { assertBound(this.stack); // check if we have an override from context - const repositoryNameOverride = this.stack.node.tryGetContext(ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY); + const repositoryNameOverride = this.stack.construct.tryGetContext(ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY); const repositoryName = asset.repositoryName ?? repositoryNameOverride ?? ASSETS_ECR_REPOSITORY_NAME; const imageTag = asset.sourceHash; const assetId = asset.sourceHash; @@ -121,7 +121,7 @@ export class LegacyStackSynthesizer implements IStackSynthesizer { file: asset.dockerFile, }; - this.stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); + this.stack.construct.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); this.addedImageAssets.add(assetId); } @@ -134,7 +134,7 @@ export class LegacyStackSynthesizer implements IStackSynthesizer { private doAddFileAsset(asset: FileAssetSource): FileAssetLocation { assertBound(this.stack); - let params = this.assetParameters.node.tryFindChild(asset.sourceHash) as FileAssetParameters; + let params = this.assetParameters.construct.tryFindChild(asset.sourceHash) as FileAssetParameters; if (!params) { params = new FileAssetParameters(this.assetParameters, asset.sourceHash); @@ -149,7 +149,7 @@ export class LegacyStackSynthesizer implements IStackSynthesizer { artifactHashParameter: params.artifactHashParameter.logicalId, }; - this.stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); + this.stack.construct.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); } const bucketName = params.bucketNameParameter.valueAsString; diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 53433d0823fbe..82c27fb5cda06 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -166,11 +166,11 @@ export class Stack extends Construct implements ITaggable { return c; } - if (!c.node.scope) { - throw new Error(`No stack could be identified for the construct at path ${construct.node.path}`); + if (!c.construct.scope) { + throw new Error(`No stack could be identified for the construct at path ${construct.construct.path}`); } - return _lookup(c.node.scope); + return _lookup(c.construct.scope); } } @@ -357,13 +357,13 @@ export class Stack extends Construct implements ITaggable { // Also use the new behavior if we are using the new CI/CD-ready synthesizer; that way // people only have to flip one flag. // eslint-disable-next-line max-len - this.artifactId = this.node.tryGetContext(cxapi.ENABLE_STACK_NAME_DUPLICATES_CONTEXT) || this.node.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) + this.artifactId = this.construct.tryGetContext(cxapi.ENABLE_STACK_NAME_DUPLICATES_CONTEXT) || this.construct.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) ? this.generateStackArtifactId() : this.stackName; this.templateFile = `${this.artifactId}.template.json`; - this.synthesizer = props.synthesizer ?? (this.node.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) + this.synthesizer = props.synthesizer ?? (this.construct.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) ? new DefaultStackSynthesizer() : new LegacyStackSynthesizer()); this.synthesizer.bind(this); @@ -591,7 +591,7 @@ export class Stack extends Construct implements ITaggable { // denominator is 2 AZs across all AWS regions. const agnostic = Token.isUnresolved(this.account) || Token.isUnresolved(this.region); if (agnostic) { - return this.node.tryGetContext(cxapi.AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY) || [ + return this.construct.tryGetContext(cxapi.AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY) || [ Fn.select(0, Fn.getAzs()), Fn.select(1, Fn.getAzs()), ]; @@ -683,12 +683,12 @@ export class Stack extends Construct implements ITaggable { const cycle = target.stackDependencyReasons(this); if (cycle !== undefined) { // eslint-disable-next-line max-len - throw new Error(`'${target.node.path}' depends on '${this.node.path}' (${cycle.join(', ')}). Adding this dependency (${reason}) would create a cyclic reference.`); + throw new Error(`'${target.construct.path}' depends on '${this.construct.path}' (${cycle.join(', ')}). Adding this dependency (${reason}) would create a cyclic reference.`); } - let dep = this._stackDependencies[target.node.uniqueId]; + let dep = this._stackDependencies[target.construct.uniqueId]; if (!dep) { - dep = this._stackDependencies[target.node.uniqueId] = { + dep = this._stackDependencies[target.construct.uniqueId] = { stack: target, reasons: [], }; @@ -698,7 +698,7 @@ export class Stack extends Construct implements ITaggable { if (process.env.CDK_DEBUG_DEPS) { // eslint-disable-next-line no-console - console.error(`[CDK_DEBUG_DEPS] stack "${this.node.path}" depends on "${target.node.path}" because: ${reason}`); + console.error(`[CDK_DEBUG_DEPS] stack "${this.construct.path}" depends on "${target.construct.path}" because: ${reason}`); } } @@ -769,9 +769,9 @@ export class Stack extends Construct implements ITaggable { * @param cfnElement The element for which the logical ID is allocated. */ protected allocateLogicalId(cfnElement: CfnElement): string { - const scopes = cfnElement.node.scopes; + const scopes = cfnElement.construct.scopes; const stackIndex = scopes.indexOf(cfnElement.stack); - const pathComponents = scopes.slice(stackIndex + 1).map(x => x.node.id); + const pathComponents = scopes.slice(stackIndex + 1).map(x => x.construct.id); return makeUniqueId(pathComponents); } @@ -800,7 +800,7 @@ export class Stack extends Construct implements ITaggable { if (this.templateOptions.transform) { // eslint-disable-next-line max-len - this.node.addWarning('This stack is using the deprecated `templateOptions.transform` property. Consider switching to `addTransform()`.'); + this.construct.addWarning('This stack is using the deprecated `templateOptions.transform` property. Consider switching to `addTransform()`.'); this.addTransform(this.templateOptions.transform); } @@ -923,7 +923,7 @@ export class Stack extends Construct implements ITaggable { * Stack artifact ID is unique within the App's Cloud Assembly. */ private generateStackArtifactId() { - return this.generateStackId(this.node.root); + return this.generateStackId(this.construct.root); } /** @@ -931,7 +931,7 @@ export class Stack extends Construct implements ITaggable { */ private generateStackId(container: IConstruct | undefined) { const rootPath = rootPathTo(this, container); - const ids = rootPath.map(c => c.node.id); + const ids = rootPath.map(c => c.construct.id); // In unit tests our Stack (which is the only component) may not have an // id, so in that case just pretend it's "Stack". @@ -1048,7 +1048,7 @@ function cfnElements(node: IConstruct, into: CfnElement[] = []): CfnElement[] { into.push(node); } - for (const child of node.node.children) { + for (const child of node.construct.children) { // Don't recurse into a substack if (Stack.isStack(child)) { continue; } @@ -1064,7 +1064,7 @@ function cfnElements(node: IConstruct, into: CfnElement[] = []): CfnElement[] { * If no ancestor is given or the ancestor is not found, return the entire root path. */ export function rootPathTo(construct: IConstruct, ancestor?: IConstruct): IConstruct[] { - const scopes = construct.node.scopes; + const scopes = construct.construct.scopes; for (let i = scopes.length - 2; i >= 0; i--) { if (scopes[i] === ancestor) { return scopes.slice(i + 1); diff --git a/packages/@aws-cdk/core/lib/stage.ts b/packages/@aws-cdk/core/lib/stage.ts index a8a0d1d18523a..fd8013cb6045b 100644 --- a/packages/@aws-cdk/core/lib/stage.ts +++ b/packages/@aws-cdk/core/lib/stage.ts @@ -73,7 +73,7 @@ export class Stage extends Construct { * @experimental */ public static of(construct: IConstruct): Stage | undefined { - return construct.node.scopes.reverse().slice(1).find(Stage.isStage); + return construct.construct.scopes.reverse().slice(1).find(Stage.isStage); } /** @@ -159,8 +159,8 @@ export class Stage extends Construct { * @experimental */ public get artifactId() { - if (!this.node.path) { return ''; } - return `assembly-${this.node.path.replace(/\//g, '-').replace(/^-+|-+$/g, '')}`; + if (!this.construct.path) { return ''; } + return `assembly-${this.construct.path.replace(/\//g, '-').replace(/^-+|-+$/g, '')}`; } /** @@ -171,7 +171,7 @@ export class Stage extends Construct { */ public synth(options: StageSynthesisOptions = { }): cxapi.CloudAssembly { if (!this.assembly || options.force) { - const runtimeInfo = this.node.tryGetContext(cxapi.DISABLE_VERSION_REPORTING) ? undefined : collectRuntimeInformation(); + const runtimeInfo = this.construct.tryGetContext(cxapi.DISABLE_VERSION_REPORTING) ? undefined : collectRuntimeInformation(); this.assembly = synthesize(this, { skipValidation: options.skipValidation, runtimeInfo, @@ -191,7 +191,7 @@ export class Stage extends Construct { // to write sub-assemblies (which must happen before we actually get to this app's // synthesize() phase). return this.parentStage - ? this.parentStage._assemblyBuilder.createNestedAssembly(this.artifactId, this.node.path) + ? this.parentStage._assemblyBuilder.createNestedAssembly(this.artifactId, this.construct.path) : new cxapi.CloudAssemblyBuilder(outdir); } } diff --git a/packages/@aws-cdk/core/test/custom-resource-provider/test.custom-resource-provider.ts b/packages/@aws-cdk/core/test/custom-resource-provider/test.custom-resource-provider.ts index ca3d8e4839241..c13231d1eac95 100644 --- a/packages/@aws-cdk/core/test/custom-resource-provider/test.custom-resource-provider.ts +++ b/packages/@aws-cdk/core/test/custom-resource-provider/test.custom-resource-provider.ts @@ -23,7 +23,7 @@ export = { // The asset hash constantly changes, so in order to not have to chase it, just look // it up from the output. - const staging = stack.node.tryFindChild('Custom:MyResourceTypeCustomResourceProvider')?.node.tryFindChild('Staging') as AssetStaging; + const staging = stack.construct.tryFindChild('Custom:MyResourceTypeCustomResourceProvider')?.construct.tryFindChild('Staging') as AssetStaging; const assetHash = staging.sourceHash; const paramNames = Object.keys(cfn.Parameters); const bucketParam = paramNames[0]; diff --git a/packages/@aws-cdk/core/test/private/test.tree-metadata.ts b/packages/@aws-cdk/core/test/private/test.tree-metadata.ts index 3ef3966b2fd95..9d3c19a811085 100644 --- a/packages/@aws-cdk/core/test/private/test.tree-metadata.ts +++ b/packages/@aws-cdk/core/test/private/test.tree-metadata.ts @@ -279,9 +279,9 @@ export = { const treeArtifact = assembly.tree(); test.ok(treeArtifact); - const treenode = app.node.findChild('Tree'); + const treenode = app.construct.findChild('Tree'); - const warn = treenode.node.metadata.find((md) => { + const warn = treenode.construct.metadata.find((md) => { return md.type === cxschema.ArtifactMetadataEntryType.WARN && /Forcing an inspect error/.test(md.data as string) && /mycfnresource/.test(md.data as string); diff --git a/packages/@aws-cdk/core/test/test.app.ts b/packages/@aws-cdk/core/test/test.app.ts index 4130fd5d2e974..7ff83ce2511e1 100644 --- a/packages/@aws-cdk/core/test/test.app.ts +++ b/packages/@aws-cdk/core/test/test.app.ts @@ -27,11 +27,11 @@ function synth(context?: { [key: string]: any }): cxapi.CloudAssembly { const c1 = new MyConstruct(stack2, 's1c2'); // add some metadata - stack1.node.addMetadata('meta', 111); - r2.node.addWarning('warning1'); - r2.node.addWarning('warning2'); - c1.node.addMetadata('meta', { key: 'value' }); - app.node.addMetadata('applevel', 123); // apps can also have metadata + stack1.construct.addMetadata('meta', 111); + r2.construct.addWarning('warning1'); + r2.construct.addWarning('warning2'); + c1.construct.addMetadata('meta', { key: 'value' }); + app.construct.addMetadata('applevel', 123); // apps can also have metadata }); } @@ -97,8 +97,8 @@ export = { key2: 'val2', }); const prog = new App(); - test.deepEqual(prog.node.tryGetContext('key1'), 'val1'); - test.deepEqual(prog.node.tryGetContext('key2'), 'val2'); + test.deepEqual(prog.construct.tryGetContext('key1'), 'val1'); + test.deepEqual(prog.construct.tryGetContext('key2'), 'val2'); test.done(); }, @@ -113,8 +113,8 @@ export = { key2: 'val4', }, }); - test.deepEqual(prog.node.tryGetContext('key1'), 'val1'); - test.deepEqual(prog.node.tryGetContext('key2'), 'val2'); + test.deepEqual(prog.construct.tryGetContext('key1'), 'val1'); + test.deepEqual(prog.construct.tryGetContext('key2'), 'val2'); test.done(); }, @@ -149,14 +149,14 @@ export = { foo: 'bar', }, }); - test.deepEqual(prog.node.tryGetContext('foo'), 'bar'); + test.deepEqual(prog.construct.tryGetContext('foo'), 'bar'); test.done(); }, 'setContext(k,v) cannot be called after stacks have been added because stacks may use the context'(test: Test) { const prog = new App(); new Stack(prog, 's1'); - test.throws(() => prog.node.setContext('foo', 'bar')); + test.throws(() => prog.construct.setContext('foo', 'bar')); test.done(); }, @@ -164,7 +164,7 @@ export = { class Child extends Construct { protected validate() { - return [`Error from ${this.node.id}`]; + return [`Error from ${this.construct.id}`]; } } @@ -360,9 +360,9 @@ export = { }, }); - test.ok(app.node.tryGetContext('isString') === 'string'); - test.ok(app.node.tryGetContext('isNumber') === 10); - test.deepEqual(app.node.tryGetContext('isObject'), { isString: 'string', isNumber: 10 }); + test.ok(app.construct.tryGetContext('isString') === 'string'); + test.ok(app.construct.tryGetContext('isNumber') === 10); + test.deepEqual(app.construct.tryGetContext('isObject'), { isString: 'string', isNumber: 10 }); test.done(); }, @@ -373,6 +373,6 @@ class MyConstruct extends Construct { super(scope, id); new CfnResource(this, 'r1', { type: 'ResourceType1' }); - new CfnResource(this, 'r2', { type: 'ResourceType2', properties: { FromContext: this.node.tryGetContext('ctx1') } }); + new CfnResource(this, 'r2', { type: 'ResourceType2', properties: { FromContext: this.construct.tryGetContext('ctx1') } }); } } diff --git a/packages/@aws-cdk/core/test/test.aspect.ts b/packages/@aws-cdk/core/test/test.aspect.ts index 90294a86055a7..424747fd80f55 100644 --- a/packages/@aws-cdk/core/test/test.aspect.ts +++ b/packages/@aws-cdk/core/test/test.aspect.ts @@ -21,7 +21,7 @@ class VisitOnce implements IAspect { class MyAspect implements IAspect { public visit(node: IConstruct): void { - node.node.addMetadata('foo', 'bar'); + node.construct.addMetadata('foo', 'bar'); } } @@ -45,16 +45,16 @@ export = { visit(construct: IConstruct) { Aspects.of(construct).add({ visit(inner: IConstruct) { - inner.node.addMetadata('test', 'would-be-ignored'); + inner.construct.addMetadata('test', 'would-be-ignored'); }, }); }, }); app.synth(); - test.deepEqual(root.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(root.node.metadata[0].data, 'We detected an Aspect was added via another Aspect, and will not be applied'); + test.deepEqual(root.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(root.construct.metadata[0].data, 'We detected an Aspect was added via another Aspect, and will not be applied'); // warning is not added to child construct - test.equal(child.node.metadata.length, 0); + test.equal(child.construct.metadata.length, 0); test.done(); }, @@ -64,13 +64,13 @@ export = { const child = new MyConstruct(root, 'ChildConstruct'); Aspects.of(root).add(new MyAspect()); app.synth(); - test.deepEqual(root.node.metadata[0].type, 'foo'); - test.deepEqual(root.node.metadata[0].data, 'bar'); - test.deepEqual(root.node.metadata[0].type, 'foo'); - test.deepEqual(child.node.metadata[0].data, 'bar'); + test.deepEqual(root.construct.metadata[0].type, 'foo'); + test.deepEqual(root.construct.metadata[0].data, 'bar'); + test.deepEqual(root.construct.metadata[0].type, 'foo'); + test.deepEqual(child.construct.metadata[0].data, 'bar'); // no warning is added - test.equal(root.node.metadata.length, 1); - test.equal(child.node.metadata.length, 1); + test.equal(root.construct.metadata.length, 1); + test.equal(child.construct.metadata.length, 1); test.done(); }, diff --git a/packages/@aws-cdk/core/test/test.assets.ts b/packages/@aws-cdk/core/test/test.assets.ts index 5f77e89db470f..a7dcfd50ed767 100644 --- a/packages/@aws-cdk/core/test/test.assets.ts +++ b/packages/@aws-cdk/core/test/test.assets.ts @@ -16,7 +16,7 @@ export = { }); // THEN - const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.ok(assetMetadata && assetMetadata.data); @@ -83,7 +83,7 @@ export = { }); // THEN - const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.ok(assetMetadata && assetMetadata.data); @@ -111,7 +111,7 @@ export = { }); // THEN - const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.ok(assetMetadata && assetMetadata.data); @@ -131,7 +131,7 @@ export = { 'addDockerImageAsset supports overriding repository name through a context key as a workaround until we have API for that'(test: Test) { // GIVEN const stack = new Stack(); - stack.node.setContext('assets-ecr-repository-name', 'my-custom-repo-name'); + stack.construct.setContext('assets-ecr-repository-name', 'my-custom-repo-name'); // WHEN stack.addDockerImageAsset({ @@ -140,7 +140,7 @@ export = { }); // THEN - const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.ok(assetMetadata && assetMetadata.data); diff --git a/packages/@aws-cdk/core/test/test.cfn-resource.ts b/packages/@aws-cdk/core/test/test.cfn-resource.ts index 5033af4b21598..7ac09497b11f7 100644 --- a/packages/@aws-cdk/core/test/test.cfn-resource.ts +++ b/packages/@aws-cdk/core/test/test.cfn-resource.ts @@ -115,7 +115,7 @@ export = nodeunit.testCase({ const r2 = new core.CfnResource(stack, 'R2', { type: 'Foo::R2' }); // also try to take a dependency on the parent of `r1` and expect the dependency not to materialize - r2.node.addDependency(subtree); + r2.construct.addDependency(subtree); // THEN - only R2 is synthesized test.deepEqual(app.synth().getStackByName(stack.stackName).template, { diff --git a/packages/@aws-cdk/core/test/test.construct.ts b/packages/@aws-cdk/core/test/test.construct.ts index 4e99c21d6f1ea..478293947a65c 100644 --- a/packages/@aws-cdk/core/test/test.construct.ts +++ b/packages/@aws-cdk/core/test/test.construct.ts @@ -8,9 +8,9 @@ import { reEnableStackTraceCollection, restoreStackTraceColection } from './util export = { 'the "Root" construct is a special construct which can be used as the root of the tree'(test: Test) { const root = new Root(); - test.equal(root.node.id, '', 'if not specified, name of a root construct is an empty string'); - test.ok(!root.node.scope, 'no parent'); - test.equal(root.node.children.length, 1); + test.equal(root.construct.id, '', 'if not specified, name of a root construct is an empty string'); + test.ok(!root.construct.scope, 'no parent'); + test.equal(root.construct.children.length, 1); test.done(); }, @@ -23,12 +23,12 @@ export = { 'construct.name returns the name of the construct'(test: Test) { const t = createTree(); - test.equal(t.child1.node.id, 'Child1'); - test.equal(t.child2.node.id, 'Child2'); - test.equal(t.child1_1.node.id, 'Child11'); - test.equal(t.child1_2.node.id, 'Child12'); - test.equal(t.child1_1_1.node.id, 'Child111'); - test.equal(t.child2_1.node.id, 'Child21'); + test.equal(t.child1.construct.id, 'Child1'); + test.equal(t.child2.construct.id, 'Child2'); + test.equal(t.child1_1.construct.id, 'Child11'); + test.equal(t.child1_2.construct.id, 'Child12'); + test.equal(t.child1_1_1.construct.id, 'Child111'); + test.equal(t.child2_1.construct.id, 'Child21'); test.done(); }, @@ -53,13 +53,13 @@ export = { 'if construct id contains path seperators, they will be replaced by double-dash'(test: Test) { const root = new Root(); const c = new Construct(root, 'Boom/Boom/Bam'); - test.deepEqual(c.node.id, 'Boom--Boom--Bam'); + test.deepEqual(c.construct.id, 'Boom--Boom--Bam'); test.done(); }, 'if "undefined" is forcefully used as an "id", it will be treated as an empty string'(test: Test) { const c = new Construct(undefined as any, undefined as any); - test.deepEqual(c.node.id, ''); + test.deepEqual(c.construct.id, ''); test.done(); }, @@ -81,17 +81,17 @@ export = { const c1 = new Construct(child2, 'My construct'); const c2 = new Construct(child1, 'My construct'); - test.deepEqual(c1.node.path, 'This is the first child/Second level/My construct'); - test.deepEqual(c2.node.path, 'This is the first child/My construct'); - test.deepEqual(c1.node.uniqueId, 'ThisisthefirstchildSecondlevelMyconstruct202131E0'); - test.deepEqual(c2.node.uniqueId, 'ThisisthefirstchildMyconstruct8C288DF9'); + test.deepEqual(c1.construct.path, 'This is the first child/Second level/My construct'); + test.deepEqual(c2.construct.path, 'This is the first child/My construct'); + test.deepEqual(c1.construct.uniqueId, 'ThisisthefirstchildSecondlevelMyconstruct202131E0'); + test.deepEqual(c2.construct.uniqueId, 'ThisisthefirstchildMyconstruct8C288DF9'); test.done(); }, 'cannot calculate uniqueId if the construct path is ["Default"]'(test: Test) { const root = new Root(); const c = new Construct(root, 'Default'); - test.throws(() => c.node.uniqueId, /Unable to calculate a unique id for an empty set of components/); + test.throws(() => c.construct.uniqueId, /Unable to calculate a unique id for an empty set of components/); test.done(); }, @@ -99,40 +99,40 @@ export = { const root = new Root(); const child = new Construct(root, 'Child1'); new Construct(root, 'Child2'); - test.equal(child.node.children.length, 0, 'no children'); - test.equal(root.node.children.length, 3, 'three children are expected'); + test.equal(child.construct.children.length, 0, 'no children'); + test.equal(root.construct.children.length, 3, 'three children are expected'); test.done(); }, 'construct.findChild(name) can be used to retrieve a child from a parent'(test: Test) { const root = new Root(); const child = new Construct(root, 'Contruct'); - test.strictEqual(root.node.tryFindChild(child.node.id), child, 'findChild(name) can be used to retrieve the child from a parent'); - test.ok(!root.node.tryFindChild('NotFound'), 'findChild(name) returns undefined if the child is not found'); + test.strictEqual(root.construct.tryFindChild(child.construct.id), child, 'findChild(name) can be used to retrieve the child from a parent'); + test.ok(!root.construct.tryFindChild('NotFound'), 'findChild(name) returns undefined if the child is not found'); test.done(); }, 'construct.getChild(name) can be used to retrieve a child from a parent'(test: Test) { const root = new Root(); const child = new Construct(root, 'Contruct'); - test.strictEqual(root.node.findChild(child.node.id), child, 'getChild(name) can be used to retrieve the child from a parent'); + test.strictEqual(root.construct.findChild(child.construct.id), child, 'getChild(name) can be used to retrieve the child from a parent'); test.throws(() => { - root.node.findChild('NotFound'); + root.construct.findChild('NotFound'); }, '', 'getChild(name) returns undefined if the child is not found'); test.done(); }, 'can remove children from the tree using tryRemoveChild()'(test: Test) { const root = new Root(); - const childrenBeforeAdding = root.node.children.length; // Invariant to adding 'Metadata' resource or not + const childrenBeforeAdding = root.construct.children.length; // Invariant to adding 'Metadata' resource or not // Add & remove const child = new Construct(root, 'Construct'); - test.equals(true, root.node.tryRemoveChild(child.node.id)); - test.equals(false, root.node.tryRemoveChild(child.node.id)); // Second time does nothing + test.equals(true, root.construct.tryRemoveChild(child.construct.id)); + test.equals(false, root.construct.tryRemoveChild(child.construct.id)); // Second time does nothing - test.equals(undefined, root.node.tryFindChild(child.node.id)); - test.equals(childrenBeforeAdding, root.node.children.length); + test.equals(undefined, root.construct.tryFindChild(child.construct.id)); + test.equals(childrenBeforeAdding, root.construct.children.length); test.done(); }, @@ -153,8 +153,8 @@ export = { }; const t = createTree(context); - test.equal(t.child1_2.node.tryGetContext('ctx1'), 12); - test.equal(t.child1_1_1.node.tryGetContext('ctx2'), 'hello'); + test.equal(t.child1_2.construct.tryGetContext('ctx1'), 12); + test.equal(t.child1_1_1.construct.tryGetContext('ctx2'), 'hello'); test.done(); }, @@ -162,34 +162,34 @@ export = { 'construct.setContext(k,v) sets context at some level and construct.getContext(key) will return the lowermost value defined in the stack'(test: Test) { const root = new Root(); const highChild = new Construct(root, 'highChild'); - highChild.node.setContext('c1', 'root'); - highChild.node.setContext('c2', 'root'); + highChild.construct.setContext('c1', 'root'); + highChild.construct.setContext('c2', 'root'); const child1 = new Construct(highChild, 'child1'); - child1.node.setContext('c2', 'child1'); - child1.node.setContext('c3', 'child1'); + child1.construct.setContext('c2', 'child1'); + child1.construct.setContext('c3', 'child1'); const child2 = new Construct(highChild, 'child2'); const child3 = new Construct(child1, 'child1child1'); - child3.node.setContext('c1', 'child3'); - child3.node.setContext('c4', 'child3'); + child3.construct.setContext('c1', 'child3'); + child3.construct.setContext('c4', 'child3'); - test.equal(highChild.node.tryGetContext('c1'), 'root'); - test.equal(highChild.node.tryGetContext('c2'), 'root'); - test.equal(highChild.node.tryGetContext('c3'), undefined); + test.equal(highChild.construct.tryGetContext('c1'), 'root'); + test.equal(highChild.construct.tryGetContext('c2'), 'root'); + test.equal(highChild.construct.tryGetContext('c3'), undefined); - test.equal(child1.node.tryGetContext('c1'), 'root'); - test.equal(child1.node.tryGetContext('c2'), 'child1'); - test.equal(child1.node.tryGetContext('c3'), 'child1'); + test.equal(child1.construct.tryGetContext('c1'), 'root'); + test.equal(child1.construct.tryGetContext('c2'), 'child1'); + test.equal(child1.construct.tryGetContext('c3'), 'child1'); - test.equal(child2.node.tryGetContext('c1'), 'root'); - test.equal(child2.node.tryGetContext('c2'), 'root'); - test.equal(child2.node.tryGetContext('c3'), undefined); + test.equal(child2.construct.tryGetContext('c1'), 'root'); + test.equal(child2.construct.tryGetContext('c2'), 'root'); + test.equal(child2.construct.tryGetContext('c3'), undefined); - test.equal(child3.node.tryGetContext('c1'), 'child3'); - test.equal(child3.node.tryGetContext('c2'), 'child1'); - test.equal(child3.node.tryGetContext('c3'), 'child1'); - test.equal(child3.node.tryGetContext('c4'), 'child3'); + test.equal(child3.construct.tryGetContext('c1'), 'child3'); + test.equal(child3.construct.tryGetContext('c2'), 'child1'); + test.equal(child3.construct.tryGetContext('c3'), 'child1'); + test.equal(child3.construct.tryGetContext('c4'), 'child3'); test.done(); }, @@ -197,29 +197,29 @@ export = { 'construct.setContext(key, value) can only be called before adding any children'(test: Test) { const root = new Root(); new Construct(root, 'child1'); - test.throws(() => root.node.setContext('k', 'v')); + test.throws(() => root.construct.setContext('k', 'v')); test.done(); }, 'fails if context key contains unresolved tokens'(test: Test) { const root = new Root(); - test.throws(() => root.node.setContext(`my-${Aws.REGION}`, 'foo'), /Invalid context key/); - test.throws(() => root.node.tryGetContext(Aws.REGION), /Invalid context key/); + test.throws(() => root.construct.setContext(`my-${Aws.REGION}`, 'foo'), /Invalid context key/); + test.throws(() => root.construct.tryGetContext(Aws.REGION), /Invalid context key/); test.done(); }, 'construct.pathParts returns an array of strings of all names from root to node'(test: Test) { const tree = createTree(); - test.deepEqual(tree.root.node.path, ''); - test.deepEqual(tree.child1_1_1.node.path, 'HighChild/Child1/Child11/Child111'); - test.deepEqual(tree.child2.node.path, 'HighChild/Child2'); + test.deepEqual(tree.root.construct.path, ''); + test.deepEqual(tree.child1_1_1.construct.path, 'HighChild/Child1/Child11/Child111'); + test.deepEqual(tree.child2.construct.path, 'HighChild/Child2'); test.done(); }, 'if a root construct has a name, it should be included in the path'(test: Test) { const tree = createTree({}); - test.deepEqual(tree.root.node.path, ''); - test.deepEqual(tree.child1_1_1.node.path, 'HighChild/Child1/Child11/Child111'); + test.deepEqual(tree.root.construct.path, ''); + test.deepEqual(tree.child1_1_1.construct.path, 'HighChild/Child1/Child11/Child111'); test.done(); }, @@ -250,31 +250,31 @@ export = { const previousValue = reEnableStackTraceCollection(); const root = new Root(); const con = new Construct(root, 'MyConstruct'); - test.deepEqual(con.node.metadata, [], 'starts empty'); + test.deepEqual(con.construct.metadata, [], 'starts empty'); - con.node.addMetadata('key', 'value'); - con.node.addMetadata('number', 103); - con.node.addMetadata('array', [ 123, 456 ]); + con.construct.addMetadata('key', 'value'); + con.construct.addMetadata('number', 103); + con.construct.addMetadata('array', [ 123, 456 ]); restoreStackTraceColection(previousValue); - test.deepEqual(con.node.metadata[0].type, 'key'); - test.deepEqual(con.node.metadata[0].data, 'value'); - test.deepEqual(con.node.metadata[1].data, 103); - test.deepEqual(con.node.metadata[2].data, [ 123, 456 ]); - test.ok(con.node.metadata[0].trace && con.node.metadata[0].trace[1].indexOf('FIND_ME') !== -1, 'First stack line should include this function\s name'); + test.deepEqual(con.construct.metadata[0].type, 'key'); + test.deepEqual(con.construct.metadata[0].data, 'value'); + test.deepEqual(con.construct.metadata[1].data, 103); + test.deepEqual(con.construct.metadata[2].data, [ 123, 456 ]); + test.ok(con.construct.metadata[0].trace && con.construct.metadata[0].trace[1].indexOf('FIND_ME') !== -1, 'First stack line should include this function\s name'); test.done(); }, 'addMetadata(type, undefined/null) is ignored'(test: Test) { const root = new Root(); const con = new Construct(root, 'Foo'); - con.node.addMetadata('Null', null); - con.node.addMetadata('Undefined', undefined); - con.node.addMetadata('True', true); - con.node.addMetadata('False', false); - con.node.addMetadata('Empty', ''); + con.construct.addMetadata('Null', null); + con.construct.addMetadata('Undefined', undefined); + con.construct.addMetadata('True', true); + con.construct.addMetadata('False', false); + con.construct.addMetadata('Empty', ''); - const exists = (key: string) => con.node.metadata.find(x => x.type === key); + const exists = (key: string) => con.construct.metadata.find(x => x.type === key); test.ok(!exists('Null')); test.ok(!exists('Undefined')); @@ -288,12 +288,12 @@ export = { const previousValue = reEnableStackTraceCollection(); const root = new Root(); const con = new Construct(root, 'MyConstruct'); - con.node.addWarning('This construct is deprecated, use the other one instead'); + con.construct.addWarning('This construct is deprecated, use the other one instead'); restoreStackTraceColection(previousValue); - test.deepEqual(con.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(con.node.metadata[0].data, 'This construct is deprecated, use the other one instead'); - test.ok(con.node.metadata[0].trace && con.node.metadata[0].trace.length > 0); + test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(con.construct.metadata[0].data, 'This construct is deprecated, use the other one instead'); + test.ok(con.construct.metadata[0].trace && con.construct.metadata[0].trace.length > 0); test.done(); }, @@ -301,12 +301,12 @@ export = { const previousValue = reEnableStackTraceCollection(); const root = new Root(); const con = new Construct(root, 'MyConstruct'); - con.node.addError('Stop!'); + con.construct.addError('Stop!'); restoreStackTraceColection(previousValue); - test.deepEqual(con.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.ERROR); - test.deepEqual(con.node.metadata[0].data, 'Stop!'); - test.ok(con.node.metadata[0].trace && con.node.metadata[0].trace.length > 0); + test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.ERROR); + test.deepEqual(con.construct.metadata[0].data, 'Stop!'); + test.ok(con.construct.metadata[0].trace && con.construct.metadata[0].trace.length > 0); test.done(); }, @@ -314,12 +314,12 @@ export = { const previousValue = reEnableStackTraceCollection(); const root = new Root(); const con = new Construct(root, 'MyConstruct'); - con.node.addInfo('Hey there, how do you do?'); + con.construct.addInfo('Hey there, how do you do?'); restoreStackTraceColection(previousValue); - test.deepEqual(con.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.INFO); - test.deepEqual(con.node.metadata[0].data, 'Hey there, how do you do?'); - test.ok(con.node.metadata[0].trace && con.node.metadata[0].trace.length > 0); + test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.INFO); + test.deepEqual(con.construct.metadata[0].data, 'Hey there, how do you do?'); + test.ok(con.construct.metadata[0].trace && con.construct.metadata[0].trace.length > 0); test.done(); }, @@ -329,12 +329,12 @@ export = { new MyBeautifulConstruct(root, 'mbc2'); new MyBeautifulConstruct(root, 'mbc3'); new MyBeautifulConstruct(root, 'mbc4'); - test.ok(root.node.children.length >= 4); + test.ok(root.construct.children.length >= 4); test.done(); }, // eslint-disable-next-line max-len - 'construct.validate() can be implemented to perform validation, ConstructNode.validate(construct.node) will return all errors from the subtree (DFS)'(test: Test) { + 'construct.validate() can be implemented to perform validation, ConstructNode.validate(construct.construct) will return all errors from the subtree (DFS)'(test: Test) { class MyConstruct extends Construct { protected validate() { @@ -375,7 +375,7 @@ export = { const stack = new TestStack(); - const errors = ConstructNode.validate(stack.node).map((v: ValidationError) => ({ path: v.source.node.path, message: v.message })); + const errors = ConstructNode.validate(stack.construct).map((v: ValidationError) => ({ path: v.source.construct.path, message: v.message })); // validate DFS test.deepEqual(errors, [ @@ -393,11 +393,11 @@ export = { class LockableConstruct extends Construct { public lockMe() { - (this.node._actualNode as any)._lock(); + (this.construct._actualNode as any)._lock(); } public unlockMe() { - (this.node._actualNode as any)._unlock(); + (this.construct._actualNode as any)._unlock(); } } @@ -435,23 +435,23 @@ export = { new Construct(c2, '5'); // THEN - test.deepEqual(c1.node.findAll().map(x => x.node.id), c1.node.findAll(ConstructOrder.PREORDER).map(x => x.node.id)); // default is PreOrder - test.deepEqual(c1.node.findAll(ConstructOrder.PREORDER).map(x => x.node.id), [ '1', '2', '4', '5', '3' ]); - test.deepEqual(c1.node.findAll(ConstructOrder.POSTORDER).map(x => x.node.id), [ '4', '5', '2', '3', '1' ]); + test.deepEqual(c1.construct.findAll().map(x => x.construct.id), c1.construct.findAll(ConstructOrder.PREORDER).map(x => x.construct.id)); // default is PreOrder + test.deepEqual(c1.construct.findAll(ConstructOrder.PREORDER).map(x => x.construct.id), [ '1', '2', '4', '5', '3' ]); + test.deepEqual(c1.construct.findAll(ConstructOrder.POSTORDER).map(x => x.construct.id), [ '4', '5', '2', '3', '1' ]); test.done(); }, 'ancestors returns a list of parents up to root'(test: Test) { const { child1_1_1 } = createTree(); - test.deepEqual(child1_1_1.node.scopes.map(x => x.node.id), [ '', 'HighChild', 'Child1', 'Child11', 'Child111' ]); + test.deepEqual(child1_1_1.construct.scopes.map(x => x.construct.id), [ '', 'HighChild', 'Child1', 'Child11', 'Child111' ]); test.done(); }, '"root" returns the root construct'(test: Test) { const { child1, child2, child1_1_1, root } = createTree(); - test.ok(child1.node.root === root); - test.ok(child2.node.root === root); - test.ok(child1_1_1.node.root === root); + test.ok(child1.construct.root === root); + test.ok(child2.construct.root === root); + test.ok(child1_1_1.construct.root === root); test.done(); }, @@ -462,7 +462,7 @@ export = { const defaultChild = new Construct(root, 'Resource'); new Construct(root, 'child2'); - test.same(root.node.defaultChild, defaultChild); + test.same(root.construct.defaultChild, defaultChild); test.done(); }, 'returns the child with id "Default"'(test: Test) { @@ -471,16 +471,16 @@ export = { const defaultChild = new Construct(root, 'Default'); new Construct(root, 'child2'); - test.same(root.node.defaultChild, defaultChild); + test.same(root.construct.defaultChild, defaultChild); test.done(); }, 'can override defaultChild'(test: Test) { const root = new Root(); new Construct(root, 'Resource'); const defaultChild = new Construct(root, 'OtherResource'); - root.node.defaultChild = defaultChild; + root.construct.defaultChild = defaultChild; - test.same(root.node.defaultChild, defaultChild); + test.same(root.construct.defaultChild, defaultChild); test.done(); }, 'returns "undefined" if there is no default'(test: Test) { @@ -488,7 +488,7 @@ export = { new Construct(root, 'child1'); new Construct(root, 'child2'); - test.equal(root.node.defaultChild, undefined); + test.equal(root.construct.defaultChild, undefined); test.done(); }, 'fails if there are both "Resource" and "Default"'(test: Test) { @@ -498,7 +498,7 @@ export = { new Construct(root, 'child2'); new Construct(root, 'Resource'); - test.throws(() => root.node.defaultChild, + test.throws(() => root.construct.defaultChild, /Cannot determine default child for . There is both a child with id "Resource" and id "Default"/); test.done(); @@ -510,7 +510,7 @@ function createTree(context?: any) { const root = new Root(); const highChild = new Construct(root, 'HighChild'); if (context) { - Object.keys(context).forEach(key => highChild.node.setContext(key, context[key])); + Object.keys(context).forEach(key => highChild.construct.setContext(key, context[key])); } const child1 = new Construct(highChild, 'Child1'); @@ -539,9 +539,9 @@ function toTreeString(node: IConstruct, depth = 0) { for (let i = 0; i < depth; ++i) { out += ' '; } - const name = node.node.id || ''; + const name = node.construct.id || ''; out += `${node.constructor.name}${name.length > 0 ? ' [' + name + ']' : ''}\n`; - for (const child of node.node.children) { + for (const child of node.construct.children) { out += toTreeString(child, depth + 1); } return out; diff --git a/packages/@aws-cdk/core/test/test.context.ts b/packages/@aws-cdk/core/test/test.context.ts index b19c2514b1786..4e4bffc743010 100644 --- a/packages/@aws-cdk/core/test/test.context.ts +++ b/packages/@aws-cdk/core/test/test.context.ts @@ -18,7 +18,7 @@ export = { test.deepEqual(before, [ 'dummy1a', 'dummy1b', 'dummy1c' ]); const key = expectedContextKey(stack); - stack.node.setContext(key, ['us-east-1a', 'us-east-1b']); + stack.construct.setContext(key, ['us-east-1a', 'us-east-1b']); const azs = stack.availabilityZones; test.deepEqual(azs, ['us-east-1a', 'us-east-1b']); @@ -32,7 +32,7 @@ export = { test.deepEqual(before, [ 'dummy1a', 'dummy1b', 'dummy1c' ]); const key = expectedContextKey(stack); - stack.node.setContext(key, 'not-a-list'); + stack.construct.setContext(key, 'not-a-list'); test.throws( () => stack.availabilityZones, @@ -149,7 +149,7 @@ export = { // NOTE: error key is inlined here because it's part of the CX-API // compatibility surface. - stack.node.setContext(contextKey, { $providerError: 'I had a boo-boo' }); + stack.construct.setContext(contextKey, { $providerError: 'I had a boo-boo' }); const construct = new Construct(stack, 'Child'); // Verify that we got the right hardcoded key above, give a descriptive error if not @@ -162,7 +162,7 @@ export = { }); // THEN - const error = construct.node.metadata.find(m => m.type === 'aws:cdk:error'); + const error = construct.construct.metadata.find(m => m.type === 'aws:cdk:error'); test.equals(error && error.data, 'I had a boo-boo'); test.done(); diff --git a/packages/@aws-cdk/core/test/test.logical-id.ts b/packages/@aws-cdk/core/test/test.logical-id.ts index 332dad2f14eba..3a804f26c19ed 100644 --- a/packages/@aws-cdk/core/test/test.logical-id.ts +++ b/packages/@aws-cdk/core/test/test.logical-id.ts @@ -209,7 +209,7 @@ export = { const ref = c1.ref; const c2 = new CfnResource(stack, 'Construct2', { type: 'R2', properties: { ReferenceToR1: ref } }); - c2.node.addDependency(c1); + c2.construct.addDependency(c1); // THEN test.deepEqual(toCloudFormation(stack), { @@ -229,8 +229,8 @@ export = { 'customize logical id allocation behavior by overriding `Stack.allocateLogicalId`'(test: Test) { class MyStack extends Stack { protected allocateLogicalId(element: CfnElement): string { - if (element.node.id === 'A') { return 'LogicalIdOfA'; } - if (element.node.id === 'B') { return 'LogicalIdOfB'; } + if (element.construct.id === 'A') { return 'LogicalIdOfA'; } + if (element.construct.id === 'B') { return 'LogicalIdOfB'; } throw new Error('Invalid element ID'); } } diff --git a/packages/@aws-cdk/core/test/test.resource.ts b/packages/@aws-cdk/core/test/test.resource.ts index bebaf2e8be1a8..6f2612f45b81d 100644 --- a/packages/@aws-cdk/core/test/test.resource.ts +++ b/packages/@aws-cdk/core/test/test.resource.ts @@ -129,8 +129,8 @@ export = { const r1 = new Counter(stack, 'Counter1', { Count: 1 }); const r2 = new Counter(stack, 'Counter2', { Count: 1 }); const r3 = new CfnResource(stack, 'Resource3', { type: 'MyResourceType' }); - r2.node.addDependency(r1); - r2.node.addDependency(r3); + r2.construct.addDependency(r1); + r2.construct.addDependency(r3); synthesize(stack); @@ -357,8 +357,8 @@ export = { const c3 = new C3(stack, 'MyC3'); const dependingResource = new CfnResource(stack, 'MyResource', { type: 'R' }); - dependingResource.node.addDependency(c1, c2); - dependingResource.node.addDependency(c3); + dependingResource.construct.addDependency(c1, c2); + dependingResource.construct.addDependency(c3); synthesize(stack); @@ -642,7 +642,7 @@ export = { '"aws:cdk:path" metadata is added if "aws:cdk:path-metadata" context is set to true'(test: Test) { const stack = new Stack(); - stack.node.setContext(cxapi.PATH_METADATA_ENABLE_CONTEXT, true); + stack.construct.setContext(cxapi.PATH_METADATA_ENABLE_CONTEXT, true); const parent = new Construct(stack, 'Parent'); @@ -667,7 +667,7 @@ export = { const resB = new CfnResource(stackB, 'Resource', { type: 'R' }); // WHEN - resB.node.addDependency(resA); + resB.construct.addDependency(resA); // THEN const assembly = app.synth(); @@ -681,7 +681,7 @@ export = { }, }, }); - test.deepEqual(stackB.dependencies.map(s => s.node.id), ['StackA']); + test.deepEqual(stackB.dependencies.map(s => s.construct.id), ['StackA']); test.done(); }, diff --git a/packages/@aws-cdk/core/test/test.stack.ts b/packages/@aws-cdk/core/test/test.stack.ts index 4eb7ab164b29c..08f86c1eba7c3 100644 --- a/packages/@aws-cdk/core/test/test.stack.ts +++ b/packages/@aws-cdk/core/test/test.stack.ts @@ -129,9 +129,9 @@ export = { const o = new CfnOutput(stack, 'MyOutput', { value: 'boom' }); const c = new CfnCondition(stack, 'MyCondition'); - test.equal(stack.node.findChild(p.node.id), p); - test.equal(stack.node.findChild(o.node.id), o); - test.equal(stack.node.findChild(c.node.id), c); + test.equal(stack.construct.findChild(p.construct.id), p); + test.equal(stack.construct.findChild(o.construct.id), o); + test.equal(stack.construct.findChild(c.construct.id), c); test.done(); }, @@ -546,7 +546,7 @@ export = { app.synth(); // THEN - test.deepEqual(stack2.dependencies.map(s => s.node.id), ['Stack1']); + test.deepEqual(stack2.dependencies.map(s => s.construct.id), ['Stack1']); test.done(); }, @@ -822,7 +822,7 @@ export = { const child = new Stack(parent, 'child'); // WHEN - child.node.addMetadata('foo', 'bar'); + child.construct.addMetadata('foo', 'bar'); // THEN const asm = app.synth(); diff --git a/packages/@aws-cdk/core/test/test.stage.ts b/packages/@aws-cdk/core/test/test.stage.ts index d93b8d2c08c38..42ddf9fb8972d 100644 --- a/packages/@aws-cdk/core/test/test.stage.ts +++ b/packages/@aws-cdk/core/test/test.stage.ts @@ -152,7 +152,7 @@ export = { // THEN app.synth(); - test.deepEqual(aspect.visits.map(c => c.node.path), [ + test.deepEqual(aspect.visits.map(c => c.construct.path), [ 'MyStage/Stack', 'MyStage/Stack/Resource', ]); @@ -172,7 +172,7 @@ export = { // THEN app.synth(); - test.deepEqual(aspect.visits.map(c => c.node.path), [ + test.deepEqual(aspect.visits.map(c => c.construct.path), [ '', 'Tree', ]); @@ -301,4 +301,4 @@ class BogusStack extends Stack { function acctRegion(s: Stack) { return [s.account, s.region]; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/core/test/test.staging.ts b/packages/@aws-cdk/core/test/test.staging.ts index 6fb2a6f80ab4b..7bd11df1f103b 100644 --- a/packages/@aws-cdk/core/test/test.staging.ts +++ b/packages/@aws-cdk/core/test/test.staging.ts @@ -47,7 +47,7 @@ export = { 'staging can be disabled through context'(test: Test) { // GIVEN const stack = new Stack(); - stack.node.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); + stack.construct.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); const sourcePath = path.join(__dirname, 'fs', 'fixtures', 'test1'); // WHEN diff --git a/packages/@aws-cdk/core/test/test.synthesis.ts b/packages/@aws-cdk/core/test/test.synthesis.ts index d83ba978bdaa3..7fde8510f398f 100644 --- a/packages/@aws-cdk/core/test/test.synthesis.ts +++ b/packages/@aws-cdk/core/test/test.synthesis.ts @@ -153,7 +153,7 @@ export = { } const root = new SynthesizeMe(); - const assembly = cdk.ConstructNode.synth(root.node, { outdir: fs.mkdtempSync(path.join(os.tmpdir(), 'outdir')) }); + const assembly = cdk.ConstructNode.synth(root.construct, { outdir: fs.mkdtempSync(path.join(os.tmpdir(), 'outdir')) }); test.deepEqual(calls, [ 'prepare', 'validate', 'synthesize' ]); const stack = assembly.getStackByName('art'); diff --git a/packages/@aws-cdk/core/test/test.util.ts b/packages/@aws-cdk/core/test/test.util.ts index 010f6ef33dc5b..986f10a5a1d1c 100644 --- a/packages/@aws-cdk/core/test/test.util.ts +++ b/packages/@aws-cdk/core/test/test.util.ts @@ -96,7 +96,7 @@ export = testCase({ test.done(); function path(s: Stack) { - return pathToTopLevelStack(s).map(x => x.node.id); + return pathToTopLevelStack(s).map(x => x.construct.id); } }, @@ -132,7 +132,7 @@ export = testCase({ function lca(s1: Stack, s2: Stack) { const res = findLastCommonElement(pathToTopLevelStack(s1), pathToTopLevelStack(s2)); if (!res) { return undefined; } - return res.node.id; + return res.construct.id; } }, }); From ae9ed6208dc81a7a38f4b9626c7c30f1811f97a9 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Mon, 10 Aug 2020 19:31:57 +0300 Subject: [PATCH 13/43] feat(core): new annotations api (#9563) In [CDK 2.0] the `node.addWarning()`, `node.addError()` and `node.addInfo()` APIs will be removed in favor of a "trait" pattern: Annotations.of(construct).addWarning(message) The existing APIs are still supported but marked as `@deprecated`. Related: https://github.com/aws/aws-cdk-rfcs/issues/192, See [Design]. [CDK 2.0]: https://github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md [Design]: https://github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#09-logging ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/core/lib/annotations.ts | 60 +++++++++++++++++++ .../@aws-cdk/core/lib/construct-compat.ts | 17 +++--- .../@aws-cdk/core/lib/context-provider.ts | 4 +- .../@aws-cdk/core/lib/private/synthesis.ts | 3 +- .../core/lib/private/tree-metadata.ts | 3 +- packages/@aws-cdk/core/lib/stack.ts | 9 +-- packages/@aws-cdk/core/test/test.app.ts | 5 +- packages/@aws-cdk/core/test/test.construct.ts | 7 ++- 8 files changed, 89 insertions(+), 19 deletions(-) create mode 100644 packages/@aws-cdk/core/lib/annotations.ts diff --git a/packages/@aws-cdk/core/lib/annotations.ts b/packages/@aws-cdk/core/lib/annotations.ts new file mode 100644 index 0000000000000..8f13e09987035 --- /dev/null +++ b/packages/@aws-cdk/core/lib/annotations.ts @@ -0,0 +1,60 @@ +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; +import { IConstruct } from './construct-compat'; + +/** + * Includes API for attaching annotations such as warning messages to constructs. + */ +export class Annotations { + /** + * Returns the annotations API for a construct scope. + * @param scope The scope + */ + public static of(scope: IConstruct) { + return new Annotations(scope); + } + + private constructor(private readonly scope: IConstruct) { + + } + + /** + * Adds a warning metadata entry to this construct. + * + * The CLI will display the warning when an app is synthesized, or fail if run + * in --strict mode. + * + * @param message The warning message. + */ + public addWarning(message: string) { + this.addMessage(cxschema.ArtifactMetadataEntryType.WARN, message); + } + + /** + * Adds an info metadata entry to this construct. + * + * The CLI will display the info message when apps are synthesized. + * + * @param message The info message. + */ + public addInfo(message: string): void { + this.addMessage(cxschema.ArtifactMetadataEntryType.INFO, message); + } + + /** + * Adds an { "error": } metadata entry to this construct. + * The toolkit will fail synthesis when errors are reported. + * @param message The error message. + */ + public addError(message: string) { + this.addMessage(cxschema.ArtifactMetadataEntryType.ERROR, message); + } + + /** + * Adds a message metadata entry to the construct node, to be displayed by the CDK CLI. + * @param level The message level + * @param message The message itself + */ + private addMessage(level: string, message: string) { + this.scope.node.addMetadata(level, message); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index 57a7269906b57..6b3832ecba636 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -10,9 +10,9 @@ * This file, in its entirety, is expected to be removed in v2.0. */ -import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; import * as constructs from 'constructs'; +import { Annotations } from './annotations'; import { IAspect, Aspects } from './aspect'; import { IDependable } from './dependency'; import { Token } from './token'; @@ -426,31 +426,34 @@ export class ConstructNode { public addMetadata(type: string, data: any, fromFunction?: any): void { this._actualNode.addMetadata(type, data, fromFunction); } /** - * Adds a { "info": } metadata entry to this construct. + * DEPRECATED: Adds a { "info": } metadata entry to this construct. * The toolkit will display the info message when apps are synthesized. * @param message The info message. + * @deprecated use `Annotations.of(construct).addInfo()` */ public addInfo(message: string): void { - this._actualNode.addMetadata(cxschema.ArtifactMetadataEntryType.INFO, message); + Annotations.of(this.host).addInfo(message); } /** - * Adds a { "warning": } metadata entry to this construct. + * DEPRECATED: Adds a { "warning": } metadata entry to this construct. * The toolkit will display the warning when an app is synthesized, or fail * if run in --strict mode. * @param message The warning message. + * @deprecated use `Annotations.of(construct).addWarning()` */ public addWarning(message: string): void { - this._actualNode.addMetadata(cxschema.ArtifactMetadataEntryType.WARN, message); + Annotations.of(this.host).addWarning(message); } /** - * Adds an { "error": } metadata entry to this construct. + * DEPRECATED: Adds an { "error": } metadata entry to this construct. * The toolkit will fail synthesis when errors are reported. * @param message The error message. + * @deprecated use `Annotations.of(construct).addError()` */ public addError(message: string) { - this._actualNode.addMetadata(cxschema.ArtifactMetadataEntryType.ERROR, message); + Annotations.of(this.host).addError(message); } /** diff --git a/packages/@aws-cdk/core/lib/context-provider.ts b/packages/@aws-cdk/core/lib/context-provider.ts index 8f0e968416c28..9d176709cb778 100644 --- a/packages/@aws-cdk/core/lib/context-provider.ts +++ b/packages/@aws-cdk/core/lib/context-provider.ts @@ -1,5 +1,6 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; +import { Annotations } from './annotations'; import { Construct } from './construct-compat'; import { Stack } from './stack'; import { Token } from './token'; @@ -107,8 +108,9 @@ export class ContextProvider { }); if (providerError !== undefined) { - scope.construct.addError(providerError); + Annotations.of(scope).addError(providerError); } + return { value: options.dummyValue }; } diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index 537c2fa3ac5ee..d335c6181dfa6 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -1,5 +1,6 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as constructs from 'constructs'; +import { Annotations } from '../annotations'; import { Aspects, IAspect } from '../aspect'; import { Construct, IConstruct, SynthesisOptions, ValidationError } from '../construct-compat'; import { Stack } from '../stack'; @@ -84,7 +85,7 @@ function invokeAspects(root: IConstruct) { // if an aspect was added to the node while invoking another aspect it will not be invoked, emit a warning // the `nestedAspectWarning` flag is used to prevent the warning from being emitted for every child if (!nestedAspectWarning && nodeAspectsCount !== aspects.aspects.length) { - construct.construct.addWarning('We detected an Aspect was added via another Aspect, and will not be applied'); + Annotations.of(construct).addWarning('We detected an Aspect was added via another Aspect, and will not be applied'); nestedAspectWarning = true; } diff --git a/packages/@aws-cdk/core/lib/private/tree-metadata.ts b/packages/@aws-cdk/core/lib/private/tree-metadata.ts index 018179c0a1388..5ff0b2a2b2ded 100644 --- a/packages/@aws-cdk/core/lib/private/tree-metadata.ts +++ b/packages/@aws-cdk/core/lib/private/tree-metadata.ts @@ -2,6 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { ArtifactType } from '@aws-cdk/cloud-assembly-schema'; +import { Annotations } from '../annotations'; import { Construct, IConstruct, ISynthesisSession } from '../construct-compat'; import { Stack } from '../stack'; import { IInspectable, TreeInspector } from '../tree'; @@ -32,7 +33,7 @@ export class TreeMetadata extends Construct { try { return visit(c); } catch (e) { - this.construct.addWarning(`Failed to render tree metadata for node [${c.construct.id}]. Reason: ${e}`); + Annotations.of(this).addWarning(`Failed to render tree metadata for node [${c.node.id}]. Reason: ${e}`); return undefined; } }); diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index 82c27fb5cda06..b30b008ab520d 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -2,6 +2,8 @@ import * as fs from 'fs'; import * as path from 'path'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; +import { Annotations } from './annotations'; +import { App } from './app'; import { Arn, ArnComponents } from './arn'; import { DockerImageAssetLocation, DockerImageAssetSource, FileAssetLocation, FileAssetSource } from './assets'; import { CfnElement } from './cfn-element'; @@ -201,7 +203,7 @@ export class Stack extends Construct implements ITaggable { * value is an unresolved token (`Token.isUnresolved(stack.region)` returns * `true`), this implies that the user wishes that this stack will synthesize * into a **region-agnostic template**. In this case, your code should either - * fail (throw an error, emit a synth error using `node.addError`) or + * fail (throw an error, emit a synth error using `Annotations.of(construct).addError()`) or * implement some other region-agnostic behavior. */ public readonly region: string; @@ -223,7 +225,7 @@ export class Stack extends Construct implements ITaggable { * value is an unresolved token (`Token.isUnresolved(stack.account)` returns * `true`), this implies that the user wishes that this stack will synthesize * into a **account-agnostic template**. In this case, your code should either - * fail (throw an error, emit a synth error using `node.addError`) or + * fail (throw an error, emit a synth error using `Annotations.of(construct).addError()`) or * implement some other region-agnostic behavior. */ public readonly account: string; @@ -800,7 +802,7 @@ export class Stack extends Construct implements ITaggable { if (this.templateOptions.transform) { // eslint-disable-next-line max-len - this.construct.addWarning('This stack is using the deprecated `templateOptions.transform` property. Consider switching to `addTransform()`.'); + Annotations.of(this).addWarning('This stack is using the deprecated `templateOptions.transform` property. Consider switching to `addTransform()`.'); this.addTransform(this.templateOptions.transform); } @@ -1094,7 +1096,6 @@ import { Stage } from './stage'; import { ITaggable, TagManager } from './tag-manager'; import { Token } from './token'; import { FileSystem } from './fs'; -import { App } from './app'; interface StackDependency { stack: Stack; diff --git a/packages/@aws-cdk/core/test/test.app.ts b/packages/@aws-cdk/core/test/test.app.ts index 7ff83ce2511e1..8e3cad39a7dc2 100644 --- a/packages/@aws-cdk/core/test/test.app.ts +++ b/packages/@aws-cdk/core/test/test.app.ts @@ -2,6 +2,7 @@ import { ContextProvider } from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; import { Test } from 'nodeunit'; import { CfnResource, Construct, Stack, StackProps } from '../lib'; +import { Annotations } from '../lib/annotations'; import { App, AppProps } from '../lib/app'; function withApp(props: AppProps, block: (app: App) => void): cxapi.CloudAssembly { @@ -28,8 +29,8 @@ function synth(context?: { [key: string]: any }): cxapi.CloudAssembly { // add some metadata stack1.construct.addMetadata('meta', 111); - r2.construct.addWarning('warning1'); - r2.construct.addWarning('warning2'); + Annotations.of(r2).addWarning('warning1'); + Annotations.of(r2).addWarning('warning2'); c1.construct.addMetadata('meta', { key: 'value' }); app.construct.addMetadata('applevel', 123); // apps can also have metadata }); diff --git a/packages/@aws-cdk/core/test/test.construct.ts b/packages/@aws-cdk/core/test/test.construct.ts index 478293947a65c..fe7eae49419ae 100644 --- a/packages/@aws-cdk/core/test/test.construct.ts +++ b/packages/@aws-cdk/core/test/test.construct.ts @@ -1,6 +1,7 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { Test } from 'nodeunit'; import { App as Root, Aws, Construct, ConstructNode, ConstructOrder, IConstruct, Lazy, ValidationError } from '../lib'; +import { Annotations } from '../lib/annotations'; import { reEnableStackTraceCollection, restoreStackTraceColection } from './util'; /* eslint-disable @typescript-eslint/naming-convention */ @@ -288,7 +289,7 @@ export = { const previousValue = reEnableStackTraceCollection(); const root = new Root(); const con = new Construct(root, 'MyConstruct'); - con.construct.addWarning('This construct is deprecated, use the other one instead'); + Annotations.of(con).addWarning('This construct is deprecated, use the other one instead'); restoreStackTraceColection(previousValue); test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); @@ -301,7 +302,7 @@ export = { const previousValue = reEnableStackTraceCollection(); const root = new Root(); const con = new Construct(root, 'MyConstruct'); - con.construct.addError('Stop!'); + Annotations.of(con).addError('Stop!'); restoreStackTraceColection(previousValue); test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.ERROR); @@ -314,7 +315,7 @@ export = { const previousValue = reEnableStackTraceCollection(); const root = new Root(); const con = new Construct(root, 'MyConstruct'); - con.construct.addInfo('Hey there, how do you do?'); + Annotations.of(con).addInfo('Hey there, how do you do?'); restoreStackTraceColection(previousValue); test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.INFO); From 41940d3cfad289cbaed8ff60a21c6c9fa9aad532 Mon Sep 17 00:00:00 2001 From: CurtisEppel Date: Tue, 11 Aug 2020 17:57:31 +1000 Subject: [PATCH 14/43] feat(cloudwatch): alarm status widget (#9456) Add support for the alarm status widget. This widget allows you to see the status of multiple alarms in a grid view. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-cloudwatch/README.md | 14 +++++ .../aws-cloudwatch/lib/alarm-status-widget.ts | 63 +++++++++++++++++++ packages/@aws-cdk/aws-cloudwatch/lib/index.ts | 1 + .../test/test.alarm-status-widget.ts | 35 +++++++++++ 4 files changed, 113 insertions(+) create mode 100644 packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts create mode 100644 packages/@aws-cdk/aws-cloudwatch/test/test.alarm-status-widget.ts diff --git a/packages/@aws-cdk/aws-cloudwatch/README.md b/packages/@aws-cdk/aws-cloudwatch/README.md index 03d0d9abeafd0..f9781b8736f9e 100644 --- a/packages/@aws-cdk/aws-cloudwatch/README.md +++ b/packages/@aws-cdk/aws-cloudwatch/README.md @@ -230,6 +230,7 @@ The following widgets are available: - `AlarmWidget` -- shows the graph and alarm line for a single alarm. - `SingleValueWidget` -- shows the current value of a set of metrics. - `TextWidget` -- shows some static Markdown. +- `AlarmStatusWidget` -- shows the status of your alarms in a grid view. ### Graph widget @@ -319,6 +320,19 @@ dashboard.addWidgets(new TextWidget({ })); ``` +### Alarm Status widget + +An alarm status widget displays instantly the status of any type of alarms and gives the +ability to aggregate one or more alarms together in a small surface. + +```ts +dashboard.addWidgets( + new AlarmStatusWidget({ + alarms: [errorAlarm], + }) +); +``` + ### Query results widget A `LogQueryWidget` shows the results of a query from Logs Insights: diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts b/packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts new file mode 100644 index 0000000000000..3562a0b9cba6b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts @@ -0,0 +1,63 @@ +import { IAlarm } from './alarm-base'; +import { ConcreteWidget } from './widget'; + +/** + * Properties for an Alarm Status Widget + */ +export interface AlarmStatusWidgetProps { + /** + * CloudWatch Alarms to show in widget + */ + readonly alarms: IAlarm[]; + /** + * The title of the widget + * + * @default 'Alarm Status' + */ + readonly title?: string; + /** + * Width of the widget, in a grid of 24 units wide + * + * @default 6 + */ + readonly width?: number; + /** + * Height of the widget + * + * @default 3 + */ + readonly height?: number; +} + +/** + * A dashboard widget that displays alarms in a grid view + */ +export class AlarmStatusWidget extends ConcreteWidget { + private readonly props: AlarmStatusWidgetProps; + + constructor(props: AlarmStatusWidgetProps) { + super(props.width || 6, props.height || 3); + this.props = props; + } + + public position(x: number, y: number): void { + this.x = x; + this.y = y; + } + + public toJson(): any[] { + return [ + { + type: 'alarm', + width: this.width, + height: this.height, + x: this.x, + y: this.y, + properties: { + title: this.props.title ? this.props.title : 'Alarm Status', + alarms: this.props.alarms.map((alarm) => alarm.alarmArn), + }, + }, + ]; + } +} diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/index.ts b/packages/@aws-cdk/aws-cloudwatch/lib/index.ts index 05d2ce4f254a6..fbbf8c7bb8b69 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/index.ts @@ -11,6 +11,7 @@ export * from './metric-types'; export * from './log-query'; export * from './text'; export * from './widget'; +export * from './alarm-status-widget'; // AWS::CloudWatch CloudFormation Resources: export * from './cloudwatch.generated'; diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.alarm-status-widget.ts b/packages/@aws-cdk/aws-cloudwatch/test/test.alarm-status-widget.ts new file mode 100644 index 0000000000000..17d24cfd3793f --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/test/test.alarm-status-widget.ts @@ -0,0 +1,35 @@ +import { Stack } from '@aws-cdk/core'; +import { Test } from 'nodeunit'; +import { Metric, Alarm, AlarmStatusWidget } from '../lib'; +export = { + 'alarm status widget'(test: Test) { + // GIVEN + const stack = new Stack(); + const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); + const alarm = new Alarm(stack, 'Alarm', { + metric, + threshold: 1, + evaluationPeriods: 1, + }); + + // WHEN + const widget = new AlarmStatusWidget({ + alarms: [alarm], + }); + + // THEN + test.deepEqual(stack.resolve(widget.toJson()), [ + { + type: 'alarm', + width: 6, + height: 3, + properties: { + title: 'Alarm Status', + alarms: [{ 'Fn::GetAtt': ['Alarm7103F465', 'Arn'] }], + }, + }, + ]); + + test.done(); + }, +}; From 1fe9684ea6b2dcaac1d97b64edfd4ef87cc65c0f Mon Sep 17 00:00:00 2001 From: flemjame-at-amazon <57235867+flemjame-at-amazon@users.noreply.github.com> Date: Tue, 11 Aug 2020 04:20:36 -0400 Subject: [PATCH 15/43] feat(global-accelerator): referencing Global Accelerator security group (#9358) ---- When using certain features of a Global Accelerator (AGA) AGA creates ENIs and a security group per VPC. Referencing this SG is needed to create security group rules in other SGs, but CloudFormation and CDK don't allow you to reference this SG. This change adds an AWS custom resource which automatically discovers the security group name so you can reference it in other constructs. *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-globalaccelerator/README.md | 37 ++++++- .../lib/accelerator-security-group.ts | 70 ++++++++++++ .../aws-globalaccelerator/lib/index.ts | 1 + .../aws-globalaccelerator/package.json | 7 +- .../globalaccelerator-security-group.test.ts | 103 ++++++++++++++++++ .../aws-globalaccelerator/test/util.ts | 2 +- 6 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 packages/@aws-cdk/aws-globalaccelerator/lib/accelerator-security-group.ts create mode 100644 packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts diff --git a/packages/@aws-cdk/aws-globalaccelerator/README.md b/packages/@aws-cdk/aws-globalaccelerator/README.md index ac304fe3ea03e..7d32fc8c72bae 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/README.md +++ b/packages/@aws-cdk/aws-globalaccelerator/README.md @@ -15,7 +15,7 @@ ## Introduction -AWS Global Accelerator is a service that improves the availability and performance of your applications with local or global users. It provides static IP addresses that act as a fixed entry point to your application endpoints in a single or multiple AWS Regions, such as your Application Load Balancers, Network Load Balancers or Amazon EC2 instances. +AWS Global Accelerator (AGA) is a service that improves the availability and performance of your applications with local or global users. It provides static IP addresses that act as a fixed entry point to your application endpoints in a single or multiple AWS Regions, such as your Application Load Balancers, Network Load Balancers or Amazon EC2 instances. This module supports features under [AWS Global Accelerator](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GlobalAccelerator.html) that allows users set up resources using the `@aws-cdk/aws-globalaccelerator` module. @@ -93,3 +93,38 @@ endpointGroup.addElasticIpAddress('EipEndpoint', eip); endpointGroup.addEc2Instance('InstanceEndpoint', instances[0]); endpointGroup.addEndpoint('InstanceEndpoint2', instances[1].instanceId); ``` + +## Accelerator Security Groups + +When using certain AGA features (client IP address preservation), AGA creates elastic network interfaces (ENI) in your AWS account which are +associated with a Security Group, and which are reused for all AGAs associated with that VPC. Per the +[best practices](https://docs.aws.amazon.com/global-accelerator/latest/dg/best-practices-aga.html) page, AGA creates a specific security group +called `GlobalAccelerator` for each VPC it has an ENI in. You can use the security group created by AGA as a source group in other security +groups, such as those for EC2 instances or Elastic Load Balancers, in order to implement least-privilege security group rules. + +CloudFormation doesn't support referencing the security group created by AGA. CDK has a library that enables you to reference the AGA security group +for a VPC using an AwsCustomResource. + +``` +const vpc = new Vpc(stack, 'VPC', {}); +const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc, internetFacing: false }); +const accelerator = new ga.Accelerator(stack, 'Accelerator'); +const listener = new ga.Listener(stack, 'Listener', { + accelerator, + portRanges: [ + { + fromPort: 443, + toPort: 443, + }, + ], +}); +const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); +endpointGroup.addLoadBalancer('AlbEndpoint', alb); + +// Remember that there is only one AGA security group per VPC. +// This code will fail at CloudFormation deployment time if you do not have an AGA +const agaSg = ga.AcceleratorSecurityGroup.fromVpc(stack, 'GlobalAcceleratorSG', vpc); + +// Allow connections from the AGA to the ALB +alb.connections.allowFrom(agaSg, Port.tcp(443)); +``` \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator-security-group.ts b/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator-security-group.ts new file mode 100644 index 0000000000000..223954e24134e --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator/lib/accelerator-security-group.ts @@ -0,0 +1,70 @@ +import { ISecurityGroup, SecurityGroup, IVpc } from '@aws-cdk/aws-ec2'; +import { Construct } from '@aws-cdk/core'; +import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId} from '@aws-cdk/custom-resources'; +import { EndpointGroup } from '../lib'; + +/** + * The security group used by a Global Accelerator to send traffic to resources in a VPC. + */ +export class AcceleratorSecurityGroup { + /** + * Lookup the Global Accelerator security group at CloudFormation deployment time. + * + * As of this writing, Global Accelerators (AGA) create a single security group per VPC. AGA security groups are shared + * by all AGAs in an account. Additionally, there is no CloudFormation mechanism to reference the AGA security groups. + * + * This makes creating security group rules which allow traffic from an AGA complicated in CDK. This lookup will identify + * the AGA security group for a given VPC at CloudFormation deployment time, and lets you create rules for traffic from AGA + * to other resources created by CDK. + */ + public static fromVpc(scope: Construct, id: string, vpc: IVpc, endpointGroup: EndpointGroup): ISecurityGroup { + + // The security group name is always 'GlobalAccelerator' + const globalAcceleratorSGName = 'GlobalAccelerator'; + + // How to reference the security group name in the response from EC2 + const ec2ResponseSGIdField = 'SecurityGroups.0.GroupId'; + + // The AWS Custom Resource that make a call to EC2 to get the security group ID, for the given VPC + const lookupAcceleratorSGCustomResource = new AwsCustomResource(scope, id + 'CustomResource', { + onCreate: { + service: 'EC2', + action: 'describeSecurityGroups', + parameters: { + Filters: [ + { + Name: 'group-name', + Values: [ + globalAcceleratorSGName, + ], + }, + { + Name: 'vpc-id', + Values: [ + vpc.vpcId, + ], + }, + ], + }, + // We get back a list of responses, but the list should be of length 0 or 1 + // Getting no response means no resources have been linked to the AGA + physicalResourceId: PhysicalResourceId.fromResponse(ec2ResponseSGIdField), + }, + policy: AwsCustomResourcePolicy.fromSdkCalls({ + resources: AwsCustomResourcePolicy.ANY_RESOURCE, + }), + }); + + // Look up the security group ID + const sg = SecurityGroup.fromSecurityGroupId(scope, + id, + lookupAcceleratorSGCustomResource.getResponseField(ec2ResponseSGIdField)); + // We add a dependency on the endpoint group, guaranteeing that CloudFormation won't + // try and look up the SG before AGA creates it. The SG is created when a VPC resource + // is associated with an AGA + lookupAcceleratorSGCustomResource.node.addDependency(endpointGroup); + return sg; + } + + private constructor() {} +} diff --git a/packages/@aws-cdk/aws-globalaccelerator/lib/index.ts b/packages/@aws-cdk/aws-globalaccelerator/lib/index.ts index ce94d8991fb5d..ff4675e6af2e5 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/lib/index.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/lib/index.ts @@ -1,5 +1,6 @@ // AWS::GlobalAccelerator CloudFormation Resources: export * from './globalaccelerator.generated'; export * from './accelerator'; +export * from './accelerator-security-group'; export * from './listener'; export * from './endpoint-group'; diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index fb84dd0d1d5eb..d9fa05dcacc62 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -66,7 +66,6 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "cdk-integ-tools": "0.0.0", "cdk-build-tools": "0.0.0", @@ -74,12 +73,16 @@ "pkglint": "0.0.0" }, "dependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.0.2" }, "peerDependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.0.2" + "constructs": "^3.0.2", + "@aws-cdk/custom-resources": "0.0.0" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts new file mode 100644 index 0000000000000..c3ca726bf344c --- /dev/null +++ b/packages/@aws-cdk/aws-globalaccelerator/test/globalaccelerator-security-group.test.ts @@ -0,0 +1,103 @@ +import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { Port } from '@aws-cdk/aws-ec2'; +import * as ga from '../lib'; +import { testFixture, testFixtureAlb } from './util'; + +test('custom resource exists', () => { + // GIVEN + const { stack, vpc } = testFixture(); + const accelerator = new ga.Accelerator(stack, 'Accelerator'); + const listener = new ga.Listener(stack, 'Listener', { + accelerator, + portRanges: [ + { + fromPort: 443, + toPort: 443, + }, + ], + }); + const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); + + // WHEN + ga.AcceleratorSecurityGroup.fromVpc(stack, 'GlobalAcceleratorSG', vpc, endpointGroup); + + // THEN + expect(stack).to(haveResource('Custom::AWS', { + Properties: { + ServiceToken: { + 'Fn::GetAtt': [ + 'AWS679f53fac002430cb0da5b7982bd22872D164C4C', + 'Arn', + ], + }, + Create: { + action: 'describeSecurityGroups', + service: 'EC2', + parameters: { + Filters: [ + { + Name: 'group-name', + Values: [ + 'GlobalAccelerator', + ], + }, + { + Name: 'vpc-id', + Values: [ + { + Ref: 'VPCB9E5F0B4', + }, + ], + }, + ], + }, + physicalResourceId: { + responsePath: 'SecurityGroups.0.GroupId', + }, + }, + }, + DependsOn: [ + 'GroupC77FDACD', + ], + }, ResourcePart.CompleteDefinition)); +}); + +test('can create security group rule', () => { + // GIVEN + const { stack, alb, vpc } = testFixtureAlb(); + const accelerator = new ga.Accelerator(stack, 'Accelerator'); + const listener = new ga.Listener(stack, 'Listener', { + accelerator, + portRanges: [ + { + fromPort: 443, + toPort: 443, + }, + ], + }); + const endpointGroup = new ga.EndpointGroup(stack, 'Group', { listener }); + endpointGroup.addLoadBalancer('endpoint', alb); + + // WHEN + const sg = ga.AcceleratorSecurityGroup.fromVpc(stack, 'GlobalAcceleratorSG', vpc, endpointGroup); + alb.connections.allowFrom(sg, Port.tcp(443)); + + // THEN + expect(stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { + IpProtocol: 'tcp', + FromPort: 443, + GroupId: { + 'Fn::GetAtt': [ + 'ALBSecurityGroup8B8624F8', + 'GroupId', + ], + }, + SourceSecurityGroupId: { + 'Fn::GetAtt': [ + 'GlobalAcceleratorSGCustomResourceC1DB5287', + 'SecurityGroups.0.GroupId', + ], + }, + ToPort: 443, + })); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator/test/util.ts b/packages/@aws-cdk/aws-globalaccelerator/test/util.ts index 03fc491788e21..56e7561565c1a 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/test/util.ts +++ b/packages/@aws-cdk/aws-globalaccelerator/test/util.ts @@ -19,7 +19,7 @@ export function testFixtureAlb() { const { stack, app, vpc } = testFixture(); const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc, internetFacing: true }); - return { stack, app, alb }; + return { stack, app, alb, vpc }; } export function testFixtureNlb() { From 60d01b132b0e76224f7aae6b6caad5d13e7a816b Mon Sep 17 00:00:00 2001 From: Christopher Rybicki Date: Tue, 11 Aug 2020 04:45:22 -0400 Subject: [PATCH 16/43] feat(iam): validate policies for missing resources/principals (#9269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds policy statement validation checks for all constructs that contain IAM policies. Fixes #7615 ---- Note: sensitive module (requires 2 PR approvers). I am not sure if the changes presented here are considered breaking or not. I'm looking to get early feedback for this commit! I'm not an IAM subject matter expert, so this is my best interpretation of the AWS docs I've read so far - but I'm still trying to figure out what details and edge cases I'm missing if any. 😅 ## Problem To recap what rix0rrr mentions in , my understanding is that there are two main kinds of IAM policies we are interested in checking: - identity-based policy: gets **attached to an IAM principal**, but **specifies the resources** it applies to - resource-based policy gets **attached to a resource**, but **specifies the IAM principal(s)** it applies to I am not aware of any other kinds of policies mentioned in the AWS docs [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) that can be constructed in the CDK. Based on [this](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policies-json) IAM docs page, it seems to me that there are at least four types of distinct policy statements errors that we could feasibly try to check right before synthesis time: 1. a resource-based policy and no principal/notPrincipal are specified 2. a identity-based policy and principal/notPrincipal are specified 3. a identity-based policy and no resources/notResources are specified 4. any kind of policy and no actions/notActions are specified The reason we need to perform these checks right before synthesis is because it can't be done at constructor time, since CDK users can add actions, principals, etc. after creation / out of order. ## Design Since we want the validation logic to happen at synthesis time, the best option is to override the validate() method for the appropriate Construct child subclasses that we want these rules to apply to. The following is the list of constructs I found that directly contain policy documents: - Role - ManagedPolicy - Policy - BucketPolicy - TopicPolicy - QueuePolicy - Repository (ECR) - Secret - Key - Alias (KMS) All other constructs that have some kind of role/policy statement functions (e.g. iam.User, lambda.Function) automatically get the validations transitively through one of the constructs above. In my commits, I've added appropriate methods to PolicyStatement and PolicyDocument to perform validation of various kinds, and then called these methods in the appropriate construct's validate() methods. ### Other considerations: It's also possible we could add calls to the PolicyStatement validation methods inside other methods such as addToResourcePolicy() found within several classes - but I think this could make the library less flexible, since a statement can still be modified after it has been added to a PolicyDocument (correct me if wrong). An alternative design I considered for the case of Resource constructs was extending the interface of IResourceWithPolicy with a validatePolicy() method, but it doesn't make a lot of sense to make the method public (which would have been required by TypeScript), and in the end all I want to do is overwrite the protected Construct#validate() method anyway. Since IResourceWithPolicy is just an interface (and not a class), I don't see any way to cleanly enforce that all Resources with policies will perform the policy validation, but I think the current solution is adequate. ## Examples These are examples of the four errors presented above that you can easily verify will fail during deployment (but aren't caught at compile or synth time), and which I've tested fail with my added changes. ``` // 1 const bucket = new s3.Bucket(this, 'TestBucket'); bucket.addToResourcePolicy(new iam.PolicyStatement({ actions: ['*'] })); // 2 const role = new iam.Role(this, 'TestRole', { assumedBy: new iam.AnyPrincipal(), }) role.attachInlinePolicy(new iam.Policy(this, 'MyPolicy', { statements: [new iam.PolicyStatement({ resources: ['*'], actions: ['*'], principals: [new iam.AnyPrincipal()] })] })); // 3 const role = new iam.Role(this, 'TestRole', { assumedBy: new iam.AccountPrincipal("457310432007"), }); role.attachInlinePolicy(new iam.Policy(this, 'MyPolicy', { statements: [new iam.PolicyStatement({ actions: ['*'], })] })); // 4 const bucket = new s3.Bucket(this, 'TestBucket') bucket.addToResourcePolicy(new iam.PolicyStatement({ principals: [new iam.AnyPrincipal()] })); ``` ## Issues - [x] Policy documents added through the "inlinePolicies" prop of iam.Role do not get validated. - [x] Add blurb about feature to [README.md](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-iam/README.md) to silence PR linter ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ecr/lib/repository.ts | 6 ++ .../@aws-cdk/aws-ecr/test/test.repository.ts | 40 ++++++++- packages/@aws-cdk/aws-iam/README.md | 3 + .../@aws-cdk/aws-iam/lib/managed-policy.ts | 2 + .../@aws-cdk/aws-iam/lib/policy-document.ts | 42 ++++++++++ .../@aws-cdk/aws-iam/lib/policy-statement.ts | 36 ++++++++ packages/@aws-cdk/aws-iam/lib/policy.ts | 2 + packages/@aws-cdk/aws-iam/lib/role.ts | 13 ++- .../aws-iam/test/managed-policy.test.ts | 18 ++++ .../aws-iam/test/policy-document.test.ts | 21 +++++ packages/@aws-cdk/aws-iam/test/policy.test.ts | 11 +++ packages/@aws-cdk/aws-iam/test/role.test.ts | 84 ++++++++++++++++++- packages/@aws-cdk/aws-kms/lib/key.ts | 6 ++ packages/@aws-cdk/aws-kms/test/test.alias.ts | 18 +++- packages/@aws-cdk/aws-kms/test/test.key.ts | 28 +++++++ .../@aws-cdk/aws-lambda/test/test.lambda.ts | 12 +-- packages/@aws-cdk/aws-s3/lib/bucket.ts | 6 ++ .../aws-s3/test/test.bucket-policy.ts | 38 ++++++++- packages/@aws-cdk/aws-s3/test/test.bucket.ts | 47 +++++++++-- .../@aws-cdk/aws-secretsmanager/lib/secret.ts | 6 ++ .../aws-secretsmanager/test/test.secret.ts | 34 ++++++++ packages/@aws-cdk/aws-sns/lib/topic-base.ts | 10 ++- packages/@aws-cdk/aws-sns/test/test.sns.ts | 46 +++++++++- packages/@aws-cdk/aws-sqs/lib/queue-base.ts | 10 ++- packages/@aws-cdk/aws-sqs/test/test.sqs.ts | 36 +++++++- 25 files changed, 548 insertions(+), 27 deletions(-) diff --git a/packages/@aws-cdk/aws-ecr/lib/repository.ts b/packages/@aws-cdk/aws-ecr/lib/repository.ts index 6a6f5b617b832..4d4c0c734443e 100644 --- a/packages/@aws-cdk/aws-ecr/lib/repository.ts +++ b/packages/@aws-cdk/aws-ecr/lib/repository.ts @@ -473,6 +473,12 @@ export class Repository extends RepositoryBase { return { statementAdded: false, policyDependable: this.policyDocument }; } + protected validate(): string[] { + const errors = super.validate(); + errors.push(...this.policyDocument?.validateForResourcePolicy() || []); + return errors; + } + /** * Add a life cycle rule to the repository * diff --git a/packages/@aws-cdk/aws-ecr/test/test.repository.ts b/packages/@aws-cdk/aws-ecr/test/test.repository.ts index f53e67310d7e5..ed97f00a408af 100644 --- a/packages/@aws-cdk/aws-ecr/test/test.repository.ts +++ b/packages/@aws-cdk/aws-ecr/test/test.repository.ts @@ -284,7 +284,10 @@ export = { const repo = new ecr.Repository(stack, 'Repo'); // WHEN - repo.addToResourcePolicy(new iam.PolicyStatement({ actions: ['*'] })); + repo.addToResourcePolicy(new iam.PolicyStatement({ + actions: ['*'], + principals: [new iam.AnyPrincipal()], + })); // THEN expect(stack).to(haveResource('AWS::ECR::Repository', { @@ -293,6 +296,7 @@ export = { { Action: '*', Effect: 'Allow', + Principal: '*', }, ], Version: '2012-10-17', @@ -302,6 +306,40 @@ export = { test.done(); }, + 'fails if repository policy has no actions'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const repo = new ecr.Repository(stack, 'Repo'); + + // WHEN + repo.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + test.done(); + }, + + 'fails if repository policy has no IAM principals'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const repo = new ecr.Repository(stack, 'Repo'); + + // WHEN + repo.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['ecr:*'], + })); + + // THEN + test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + test.done(); + }, + 'events': { 'onImagePushed without imageTag creates the correct event'(test: Test) { const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-iam/README.md b/packages/@aws-cdk/aws-iam/README.md index 3908a58d668e4..9e4db8498e2c1 100644 --- a/packages/@aws-cdk/aws-iam/README.md +++ b/packages/@aws-cdk/aws-iam/README.md @@ -313,3 +313,6 @@ const principal = new iam.OpenIdConnectPrincipal(provider); * Policy name uniqueness is enforced. If two policies by the same name are attached to the same principal, the attachment will fail. * Policy names are not required - the CDK logical ID will be used and ensured to be unique. + * Policies are validated during synthesis to ensure that they have actions, and that policies + attached to IAM principals specify relevant resources, while policies attached to resources + specify which IAM principals they apply to. diff --git a/packages/@aws-cdk/aws-iam/lib/managed-policy.ts b/packages/@aws-cdk/aws-iam/lib/managed-policy.ts index c297e03b0f9f1..c6701a8834349 100644 --- a/packages/@aws-cdk/aws-iam/lib/managed-policy.ts +++ b/packages/@aws-cdk/aws-iam/lib/managed-policy.ts @@ -294,6 +294,8 @@ export class ManagedPolicy extends Resource implements IManagedPolicy { result.push('Managed Policy is empty. You must add statements to the policy'); } + result.push(...this.document.validateForIdentityPolicy()); + return result; } } diff --git a/packages/@aws-cdk/aws-iam/lib/policy-document.ts b/packages/@aws-cdk/aws-iam/lib/policy-document.ts index 8e2b6979c28c1..da43cce541158 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy-document.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy-document.ts @@ -98,6 +98,48 @@ export class PolicyDocument implements cdk.IResolvable { return this.render(); } + /** + * Validate that all policy statements in the policy document satisfies the + * requirements for any policy. + * + * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policies-json + */ + public validateForAnyPolicy(): string[] { + const errors = new Array(); + for (const statement of this.statements) { + errors.push(...statement.validateForAnyPolicy()); + } + return errors; + } + + /** + * Validate that all policy statements in the policy document satisfies the + * requirements for a resource-based policy. + * + * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policies-json + */ + public validateForResourcePolicy(): string[] { + const errors = new Array(); + for (const statement of this.statements) { + errors.push(...statement.validateForResourcePolicy()); + } + return errors; + } + + /** + * Validate that all policy statements in the policy document satisfies the + * requirements for an identity-based policy. + * + * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policies-json + */ + public validateForIdentityPolicy(): string[] { + const errors = new Array(); + for (const statement of this.statements) { + errors.push(...statement.validateForIdentityPolicy()); + } + return errors; + } + private render(): any { if (this.isEmpty) { return undefined; diff --git a/packages/@aws-cdk/aws-iam/lib/policy-statement.ts b/packages/@aws-cdk/aws-iam/lib/policy-statement.ts index 24d99386a2391..c8688e0b6198e 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy-statement.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy-statement.ts @@ -408,6 +408,42 @@ export class PolicyStatement { } this.addConditions(conditions); } + + /** + * Validate that the policy statement satisfies base requirements for a policy. + */ + public validateForAnyPolicy(): string[] { + const errors = new Array(); + if (this.action.length === 0 && this.notAction.length === 0) { + errors.push('A PolicyStatement must specify at least one \'action\' or \'notAction\'.'); + } + return errors; + } + + /** + * Validate that the policy statement satisfies all requirements for a resource-based policy. + */ + public validateForResourcePolicy(): string[] { + const errors = this.validateForAnyPolicy(); + if (Object.keys(this.principal).length === 0 && Object.keys(this.notPrincipal).length === 0) { + errors.push('A PolicyStatement used in a resource-based policy must specify at least one IAM principal.'); + } + return errors; + } + + /** + * Validate that the policy statement satisfies all requirements for an identity-based policy. + */ + public validateForIdentityPolicy(): string[] { + const errors = this.validateForAnyPolicy(); + if (Object.keys(this.principal).length > 0 || Object.keys(this.notPrincipal).length > 0) { + errors.push('A PolicyStatement used in an identity-based policy cannot specify any IAM principals.'); + } + if (Object.keys(this.resource).length === 0 && Object.keys(this.notResource).length === 0) { + errors.push('A PolicyStatement used in an identity-based policy must specify at least one resource.'); + } + return errors; + } } /** diff --git a/packages/@aws-cdk/aws-iam/lib/policy.ts b/packages/@aws-cdk/aws-iam/lib/policy.ts index 792f0f5861186..1d1441f710128 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy.ts @@ -232,6 +232,8 @@ export class Policy extends Resource implements IPolicy { } } + result.push(...this.document.validateForIdentityPolicy()); + return result; } diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index 8b62425be50c6..23cde93dc101c 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -292,6 +292,7 @@ export class Role extends Resource implements IRole { private defaultPolicy?: Policy; private readonly managedPolicies: IManagedPolicy[] = []; private readonly attachedPolicies = new AttachedPolicies(); + private readonly inlinePolicies: { [name: string]: PolicyDocument }; private immutableRole?: IRole; constructor(scope: Construct, id: string, props: RoleProps) { @@ -306,6 +307,7 @@ export class Role extends Resource implements IRole { this.assumeRolePolicy = createAssumeRolePolicy(props.assumedBy, externalIds); this.managedPolicies.push(...props.managedPolicies || []); + this.inlinePolicies = props.inlinePolicies || {}; this.permissionsBoundary = props.permissionsBoundary; const maxSessionDuration = props.maxSessionDuration && props.maxSessionDuration.toSeconds(); validateMaxSessionDuration(maxSessionDuration); @@ -318,7 +320,7 @@ export class Role extends Resource implements IRole { const role = new CfnRole(this, 'Resource', { assumeRolePolicyDocument: this.assumeRolePolicy as any, managedPolicyArns: Lazy.listValue({ produce: () => this.managedPolicies.map(p => p.managedPolicyArn) }, { omitEmpty: true }), - policies: _flatten(props.inlinePolicies), + policies: _flatten(this.inlinePolicies), path: props.path, permissionsBoundary: this.permissionsBoundary ? this.permissionsBoundary.managedPolicyArn : undefined, roleName: this.physicalName, @@ -420,6 +422,15 @@ export class Role extends Resource implements IRole { return this.immutableRole; } + + protected validate(): string[] { + const errors = super.validate(); + errors.push(...this.assumeRolePolicy?.validateForResourcePolicy() || []); + for (const policy of Object.values(this.inlinePolicies)) { + errors.push(...policy.validateForIdentityPolicy()); + } + return errors; + } } /** diff --git a/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts b/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts index 1e1891eaa58af..edf6a3e963efc 100644 --- a/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts +++ b/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts @@ -547,12 +547,30 @@ describe('managed policy', () => { }); }); + test('fails if policy document does not specify resources', () => { + new ManagedPolicy(stack, 'MyManagedPolicy', { statements: [ + new PolicyStatement({ actions: ['*'] }), + ] }); + + expect(() => app.synth()).toThrow(/A PolicyStatement used in an identity-based policy must specify at least one resource/); + }); + + + test('fails if policy document specifies principals', () => { + new ManagedPolicy(stack, 'MyManagedPolicy', { statements: [ + new PolicyStatement({ actions: ['*'], resources: ['*'], principals: [new ServicePrincipal('test.service')] }), + ] }); + + expect(() => app.synth()).toThrow(/A PolicyStatement used in an identity-based policy cannot specify any IAM principals/); + }); + test('cross-stack hard-name contains the right resource type', () => { const mp = new ManagedPolicy(stack, 'Policy', { managedPolicyName: cdk.PhysicalName.GENERATE_IF_NEEDED, }); mp.addStatements(new PolicyStatement({ actions: ['a:abc'], + resources: ['*'], })); const stack2 = new cdk.Stack(app, 'Stack2', { env: { account: '5678', region: 'us-east-1' }}); diff --git a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts index 8de3aa2f56b0f..7b5a673c19868 100644 --- a/packages/@aws-cdk/aws-iam/test/policy-document.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy-document.test.ts @@ -725,4 +725,25 @@ describe('IAM policy document', () => { Condition: {StringEquals: {'kms:ViaService': 'service', 'sts:ExternalId': '12221121221'}}, }); }); + + test('validation error if policy statement has no actions', () => { + const policyStatement = new PolicyStatement({ + principals: [new AnyPrincipal()], + }); + + // THEN + const validationErrorsForResourcePolicy: string[] = policyStatement.validateForResourcePolicy(); + // const validationErrorsForIdentityPolicy: string[] = policyStatement.validateForIdentityPolicy(); + expect(validationErrorsForResourcePolicy).toEqual(['A PolicyStatement must specify at least one \'action\' or \'notAction\'.']); + }); + + test('validation error if policy statement for resource-based policy has no principals specified', () => { + const policyStatement = new PolicyStatement({ + actions: ['*'], + }); + + // THEN + const validationErrors: string[] = policyStatement.validateForResourcePolicy(); + expect(validationErrors).toEqual(['A PolicyStatement used in a resource-based policy must specify at least one IAM principal.']); + }); }); diff --git a/packages/@aws-cdk/aws-iam/test/policy.test.ts b/packages/@aws-cdk/aws-iam/test/policy.test.ts index 479476854b6c3..5bd50db9fd64f 100644 --- a/packages/@aws-cdk/aws-iam/test/policy.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy.test.ts @@ -310,6 +310,17 @@ describe('IAM policy', () => { expect(() => app.synth()).toThrow(/must contain at least one statement/); }); + + test('fails if policy document is invalid', () => { + new Policy(stack, 'MyRole', { + statements: [new PolicyStatement({ + actions: ['*'], + principals: [new ServicePrincipal('test.service')], + })], + }); + + expect(() => app.synth()).toThrow(/A PolicyStatement used in an identity-based policy cannot specify any IAM principals/); + }); }); function createPolicyWithLogicalId(stack: Stack, logicalId: string): void { diff --git a/packages/@aws-cdk/aws-iam/test/role.test.ts b/packages/@aws-cdk/aws-iam/test/role.test.ts index 27e67a5c3e6bd..613a66e9826cf 100644 --- a/packages/@aws-cdk/aws-iam/test/role.test.ts +++ b/packages/@aws-cdk/aws-iam/test/role.test.ts @@ -1,6 +1,6 @@ import '@aws-cdk/assert/jest'; -import { Duration, Stack } from '@aws-cdk/core'; -import { AnyPrincipal, ArnPrincipal, CompositePrincipal, FederatedPrincipal, ManagedPolicy, PolicyStatement, Role, ServicePrincipal, User } from '../lib'; +import { Duration, Stack, App } from '@aws-cdk/core'; +import { AnyPrincipal, ArnPrincipal, CompositePrincipal, FederatedPrincipal, ManagedPolicy, PolicyStatement, Role, ServicePrincipal, User, Policy, PolicyDocument } from '../lib'; describe('IAM role', () => { test('default role', () => { @@ -406,4 +406,84 @@ describe('IAM role', () => { }); }).toThrow(/Role description must be no longer than 1000 characters./); }); + + test('fails if managed policy is invalid', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + new Role(stack, 'MyRole', { + assumedBy: new ServicePrincipal('sns.amazonaws.com'), + managedPolicies: [new ManagedPolicy(stack, 'MyManagedPolicy', { + statements: [new PolicyStatement({ + resources: ['*'], + actions: ['*'], + principals: [new ServicePrincipal('sns.amazonaws.com')], + })], + })], + }); + + expect(() => app.synth()).toThrow(/A PolicyStatement used in an identity-based policy cannot specify any IAM principals/); + }); + + test('fails if default role policy is invalid', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const role = new Role(stack, 'MyRole', { + assumedBy: new ServicePrincipal('sns.amazonaws.com'), + }); + role.addToPrincipalPolicy(new PolicyStatement({ + resources: ['*'], + actions: ['*'], + principals: [new ServicePrincipal('sns.amazonaws.com')], + })); + + expect(() => app.synth()).toThrow(/A PolicyStatement used in an identity-based policy cannot specify any IAM principals/); + }); + + test('fails if inline policy from props is invalid', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + new Role(stack, 'MyRole', { + assumedBy: new ServicePrincipal('sns.amazonaws.com'), + inlinePolicies: { + testPolicy: new PolicyDocument({ + statements: [new PolicyStatement({ + resources: ['*'], + actions: ['*'], + principals: [new ServicePrincipal('sns.amazonaws.com')], + })], + }), + }, + }); + + expect(() => app.synth()).toThrow(/A PolicyStatement used in an identity-based policy cannot specify any IAM principals/); + }); + + test('fails if attached inline policy is invalid', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const role = new Role(stack, 'MyRole', { + assumedBy: new ServicePrincipal('sns.amazonaws.com'), + }); + role.attachInlinePolicy(new Policy(stack, 'MyPolicy', { + statements: [new PolicyStatement({ + resources: ['*'], + actions: ['*'], + principals: [new ServicePrincipal('sns.amazonaws.com')], + })], + })); + + expect(() => app.synth()).toThrow(/A PolicyStatement used in an identity-based policy cannot specify any IAM principals/); + }); + + test('fails if assumeRolePolicy is invalid', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const role = new Role(stack, 'MyRole', { + assumedBy: new ServicePrincipal('sns.amazonaws.com'), + managedPolicies: [new ManagedPolicy(stack, 'MyManagedPolicy')], + }); + role.assumeRolePolicy?.addStatements(new PolicyStatement({ actions: ['*'] })); + + expect(() => app.synth()).toThrow(/A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + }); }); diff --git a/packages/@aws-cdk/aws-kms/lib/key.ts b/packages/@aws-cdk/aws-kms/lib/key.ts index 2edcbafa45e84..8c565776680df 100644 --- a/packages/@aws-cdk/aws-kms/lib/key.ts +++ b/packages/@aws-cdk/aws-kms/lib/key.ts @@ -119,6 +119,12 @@ abstract class KeyBase extends Resource implements IKey { return { statementAdded: true, policyDependable: this.policy }; } + public validate(): string[] { + const errors = super.validate(); + errors.push(...this.policy?.validateForResourcePolicy() || []); + return errors; + } + /** * Grant the indicated permissions on this key to the given principal * diff --git a/packages/@aws-cdk/aws-kms/test/test.alias.ts b/packages/@aws-cdk/aws-kms/test/test.alias.ts index dc931220febaa..4da968e09730b 100644 --- a/packages/@aws-cdk/aws-kms/test/test.alias.ts +++ b/packages/@aws-cdk/aws-kms/test/test.alias.ts @@ -1,4 +1,5 @@ import { expect, haveResource, SynthUtils } from '@aws-cdk/assert'; +import { ArnPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; import { App, CfnOutput, Construct, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Alias } from '../lib/alias'; @@ -223,8 +224,23 @@ export = { const myAlias = Alias.fromAliasName(stack, 'MyAlias', 'alias/myAlias'); - test.throws(() => myAlias.aliasTargetKey, 'Cannot access aliasTargetKey on an Alias imnported by Alias.fromAliasName().'); + test.throws(() => myAlias.aliasTargetKey, 'Cannot access aliasTargetKey on an Alias imported by Alias.fromAliasName().'); test.done(); }, + + 'fails if alias policy is invalid'(test: Test) { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const key = new Key(stack, 'MyKey'); + const alias = new Alias(stack, 'Alias', { targetKey: key, aliasName: 'alias/foo' }); + + alias.addToResourcePolicy(new PolicyStatement({ + resources: ['*'], + principals: [new ArnPrincipal('arn')], + })); + + test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-kms/test/test.key.ts b/packages/@aws-cdk/aws-kms/test/test.key.ts index 05ff62d596a67..a428ea1c05f73 100644 --- a/packages/@aws-cdk/aws-kms/test/test.key.ts +++ b/packages/@aws-cdk/aws-kms/test/test.key.ts @@ -436,6 +436,34 @@ export = { test.done(); }, + 'fails if key policy has no actions'(test: Test) { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const key = new Key(stack, 'MyKey'); + + key.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + test.done(); + }, + + 'fails if key policy has no IAM principals'(test: Test) { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const key = new Key(stack, 'MyKey'); + + key.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['kms:*'], + })); + + test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + test.done(); + }, + 'imported keys': { 'throw an error when providing something that is not a valid key ARN'(test: Test) { const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts index 2cecb63d05c08..8658c0be4ec13 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts @@ -237,7 +237,7 @@ export = { const role = new iam.Role(stack, 'SomeRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), }); - role.addToPolicy(new iam.PolicyStatement({ actions: ['confirm:itsthesame'] })); + role.addToPolicy(new iam.PolicyStatement({ actions: ['confirm:itsthesame'], resources: ['*'] })); // WHEN const fn = new lambda.Function(stack, 'Function', { @@ -246,20 +246,20 @@ export = { handler: 'index.test', role, initialPolicy: [ - new iam.PolicyStatement({ actions: ['inline:inline'] }), + new iam.PolicyStatement({ actions: ['inline:inline'], resources: ['*'] }), ], }); - fn.addToRolePolicy(new iam.PolicyStatement({ actions: ['explicit:explicit'] })); + fn.addToRolePolicy(new iam.PolicyStatement({ actions: ['explicit:explicit'], resources: ['*'] })); // THEN expect(stack).to(haveResource('AWS::IAM::Policy', { 'PolicyDocument': { 'Version': '2012-10-17', 'Statement': [ - { 'Action': 'confirm:itsthesame', 'Effect': 'Allow' }, - { 'Action': 'inline:inline', 'Effect': 'Allow' }, - { 'Action': 'explicit:explicit', 'Effect': 'Allow' }, + { 'Action': 'confirm:itsthesame', 'Effect': 'Allow', 'Resource': '*' }, + { 'Action': 'inline:inline', 'Effect': 'Allow', 'Resource': '*' }, + { 'Action': 'explicit:explicit', 'Effect': 'Allow', 'Resource': '*' }, ], }, })); diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 29327a1685bf6..acb1949b1cb2e 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -448,6 +448,12 @@ abstract class BucketBase extends Resource implements IBucket { return { statementAdded: false }; } + protected validate(): string[] { + const errors = super.validate(); + errors.push(...this.policy?.document.validateForResourcePolicy() || []); + return errors; + } + /** * The https URL of an S3 object. For example: * @example https://s3.us-west-1.amazonaws.com/onlybucket diff --git a/packages/@aws-cdk/aws-s3/test/test.bucket-policy.ts b/packages/@aws-cdk/aws-s3/test/test.bucket-policy.ts index d09b566e56905..d99ddbc1cac84 100644 --- a/packages/@aws-cdk/aws-s3/test/test.bucket-policy.ts +++ b/packages/@aws-cdk/aws-s3/test/test.bucket-policy.ts @@ -1,6 +1,6 @@ import { expect, haveResource } from '@aws-cdk/assert'; -import { PolicyStatement } from '@aws-cdk/aws-iam'; -import { RemovalPolicy, Stack } from '@aws-cdk/core'; +import { AnyPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; +import { RemovalPolicy, Stack, App } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as s3 from '../lib'; @@ -18,6 +18,7 @@ export = { myBucketPolicy.document.addStatements(new PolicyStatement({ resources: [myBucket.bucketArn], actions: ['s3:GetObject*'], + principals: [new AnyPrincipal()], })); expect(stack).to(haveResource('AWS::S3::BucketPolicy', { @@ -30,6 +31,7 @@ export = { { 'Action': 's3:GetObject*', 'Effect': 'Allow', + 'Principal': '*', 'Resource': { 'Fn::GetAtt': ['MyBucketF68F3FF0', 'Arn'] }, }, ], @@ -50,6 +52,7 @@ export = { myBucketPolicy.document.addStatements(new PolicyStatement({ resources: [myBucket.bucketArn], actions: ['s3:GetObject*'], + principals: [new AnyPrincipal()], })); expect(stack).toMatch({ @@ -70,6 +73,7 @@ export = { { 'Action': 's3:GetObject*', 'Effect': 'Allow', + 'Principal': '*', 'Resource': { 'Fn::GetAtt': ['MyBucketF68F3FF0', 'Arn'] }, }, ], @@ -92,6 +96,7 @@ export = { myBucket.addToResourcePolicy(new PolicyStatement({ resources: [myBucket.bucketArn], actions: ['s3:GetObject*'], + principals: [new AnyPrincipal()], })); myBucket.policy?.applyRemovalPolicy(RemovalPolicy.RETAIN); @@ -113,6 +118,7 @@ export = { { 'Action': 's3:GetObject*', 'Effect': 'Allow', + 'Principal': '*', 'Resource': { 'Fn::GetAtt': ['MyBucketF68F3FF0', 'Arn'] }, }, ], @@ -127,4 +133,32 @@ export = { test.done(); }, + + 'fails if bucket policy has no actions'(test: Test) { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const myBucket = new s3.Bucket(stack, 'MyBucket'); + myBucket.addToResourcePolicy(new PolicyStatement({ + resources: [myBucket.bucketArn], + principals: [new AnyPrincipal()], + })); + + test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + + test.done(); + }, + + 'fails if bucket policy has no IAM principals'(test: Test) { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const myBucket = new s3.Bucket(stack, 'MyBucket'); + myBucket.addToResourcePolicy(new PolicyStatement({ + resources: [myBucket.bucketArn], + actions: ['s3:GetObject*'], + })); + + test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + + test.done(); + }, }; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/test/test.bucket.ts b/packages/@aws-cdk/aws-s3/test/test.bucket.ts index 8d78477e073d1..17d25985661cc 100644 --- a/packages/@aws-cdk/aws-s3/test/test.bucket.ts +++ b/packages/@aws-cdk/aws-s3/test/test.bucket.ts @@ -459,7 +459,11 @@ export = { const stack = new cdk.Stack(); const bucket = new s3.Bucket(stack, 'MyBucket', { encryption: s3.BucketEncryption.UNENCRYPTED }); - bucket.addToResourcePolicy(new iam.PolicyStatement({ resources: ['foo'], actions: [ 'bar:baz' ]})); + bucket.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['foo'], + actions: ['bar:baz'], + principals: [new iam.AnyPrincipal()], + })); expect(stack).toMatch({ 'Resources': { @@ -479,6 +483,7 @@ export = { { 'Action': 'bar:baz', 'Effect': 'Allow', + 'Principal': '*', 'Resource': 'foo', }, ], @@ -497,11 +502,16 @@ export = { const bucket = new s3.Bucket(stack, 'MyBucket', { encryption: s3.BucketEncryption.UNENCRYPTED }); - const x = new iam.PolicyStatement({ resources: [bucket.bucketArn], actions: ['s3:ListBucket'] }); + const x = new iam.PolicyStatement({ + resources: [bucket.bucketArn], + actions: ['s3:ListBucket'], + principals: [new iam.AnyPrincipal()], + }); test.deepEqual(stack.resolve(x.toStatementJson()), { Action: 's3:ListBucket', Effect: 'Allow', + Principal: '*', Resource: { 'Fn::GetAtt': ['MyBucketF68F3FF0', 'Arn'] }, }); @@ -513,11 +523,16 @@ export = { const bucket = new s3.Bucket(stack, 'MyBucket', { encryption: s3.BucketEncryption.UNENCRYPTED }); - const p = new iam.PolicyStatement({ resources: [bucket.arnForObjects('hello/world')], actions: ['s3:GetObject'] }); + const p = new iam.PolicyStatement({ + resources: [bucket.arnForObjects('hello/world')], + actions: ['s3:GetObject'], + principals: [new iam.AnyPrincipal()], + }); test.deepEqual(stack.resolve(p.toStatementJson()), { Action: 's3:GetObject', Effect: 'Allow', + Principal: '*', Resource: { 'Fn::Join': [ '', @@ -539,11 +554,16 @@ export = { const team = new iam.Group(stack, 'MyTeam'); const resource = bucket.arnForObjects(`home/${team.groupName}/${user.userName}/*`); - const p = new iam.PolicyStatement({ resources: [resource], actions: ['s3:GetObject'] }); + const p = new iam.PolicyStatement({ + resources: [resource], + actions: ['s3:GetObject'], + principals: [new iam.AnyPrincipal()], + }); test.deepEqual(stack.resolve(p.toStatementJson()), { Action: 's3:GetObject', Effect: 'Allow', + Principal: '*', Resource: { 'Fn::Join': [ '', @@ -592,14 +612,23 @@ export = { const bucket = s3.Bucket.fromBucketAttributes(stack, 'ImportedBucket', { bucketArn }); // this is a no-op since the bucket is external - bucket.addToResourcePolicy(new iam.PolicyStatement({ resources: ['foo'], actions: ['bar:baz']})); + bucket.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['foo'], + actions: ['bar:baz'], + principals: [new iam.AnyPrincipal()], + })); - const p = new iam.PolicyStatement({ resources: [bucket.bucketArn], actions: ['s3:ListBucket'] }); + const p = new iam.PolicyStatement({ + resources: [bucket.bucketArn], + actions: ['s3:ListBucket'], + principals: [new iam.AnyPrincipal()], + }); // it is possible to obtain a permission statement for a ref test.deepEqual(p.toStatementJson(), { Action: 's3:ListBucket', Effect: 'Allow', + Principal: '*', Resource: 'arn:aws:s3:::my-bucket', }); @@ -613,7 +642,11 @@ export = { 'import does not create any resources'(test: Test) { const stack = new cdk.Stack(); const bucket = s3.Bucket.fromBucketAttributes(stack, 'ImportedBucket', { bucketArn: 'arn:aws:s3:::my-bucket' }); - bucket.addToResourcePolicy(new iam.PolicyStatement({ resources: ['*'], actions: ['*'] })); + bucket.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['*'], + principals: [new iam.AnyPrincipal()], + })); // at this point we technically didn't create any resources in the consuming stack. expect(stack).toMatch({}); diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index 787d832764d54..1a256fb66aefd 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -208,6 +208,12 @@ abstract class SecretBase extends Resource implements ISecret { return { statementAdded: false }; } + protected validate(): string[] { + const errors = super.validate(); + errors.push(...this.policy?.document.validateForResourcePolicy() || []); + return errors; + } + public denyAccountRootDelete() { this.addToResourcePolicy(new iam.PolicyStatement({ actions: ['secretsmanager:DeleteSecret'], diff --git a/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts b/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts index 89767231ee750..0a295747e7e5f 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts @@ -621,4 +621,38 @@ export = { test.done(); }, + + 'fails if secret policy has no actions'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const secret = new secretsmanager.Secret(stack, 'Secret'); + + // WHEN + secret.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + test.done(); + }, + + 'fails if secret policy has no IAM principals'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const secret = new secretsmanager.Secret(stack, 'Secret'); + + // WHEN + secret.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['secretsmanager:*'], + })); + + // THEN + test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-sns/lib/topic-base.ts b/packages/@aws-cdk/aws-sns/lib/topic-base.ts index 263f4cf80aefa..07b96a34629d2 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic-base.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic-base.ts @@ -32,7 +32,7 @@ export interface ITopic extends IResource { * * If this topic was created in this stack (`new Topic`), a topic policy * will be automatically created upon the first call to `addToPolicy`. If - * the topic is improted (`Topic.import`), then this is a no-op. + * the topic is imported (`Topic.import`), then this is a no-op. */ addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult; @@ -88,7 +88,7 @@ export abstract class TopicBase extends Resource implements ITopic { * * If this topic was created in this stack (`new Topic`), a topic policy * will be automatically created upon the first call to `addToPolicy`. If - * the topic is improted (`Topic.import`), then this is a no-op. + * the topic is imported (`Topic.import`), then this is a no-op. */ public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { if (!this.policy && this.autoCreatePolicy) { @@ -102,6 +102,12 @@ export abstract class TopicBase extends Resource implements ITopic { return { statementAdded: false }; } + protected validate(): string[] { + const errors = super.validate(); + errors.push(...this.policy?.document.validateForResourcePolicy() || []); + return errors; + } + /** * Grant topic publishing permissions to the given identity */ diff --git a/packages/@aws-cdk/aws-sns/test/test.sns.ts b/packages/@aws-cdk/aws-sns/test/test.sns.ts index 87d1b899559e0..6f11e0ce6d370 100644 --- a/packages/@aws-cdk/aws-sns/test/test.sns.ts +++ b/packages/@aws-cdk/aws-sns/test/test.sns.ts @@ -165,8 +165,14 @@ export = { const topic = new sns.Topic(stack, 'MyTopic'); - topic.addToResourcePolicy(new iam.PolicyStatement({ actions: ['service:statement0'] })); - topic.addToResourcePolicy(new iam.PolicyStatement({ actions: ['service:statement1'] })); + topic.addToResourcePolicy(new iam.PolicyStatement({ + actions: ['service:statement0'], + principals: [new iam.ArnPrincipal('arn')], + })); + topic.addToResourcePolicy(new iam.PolicyStatement({ + actions: ['service:statement1'], + principals: [new iam.ArnPrincipal('arn')], + })); expect(stack).toMatch({ 'Resources': { @@ -181,11 +187,13 @@ export = { { 'Action': 'service:statement0', 'Effect': 'Allow', + 'Principal': { 'AWS': 'arn' }, 'Sid': '0', }, { 'Action': 'service:statement1', 'Effect': 'Allow', + 'Principal': { 'AWS': 'arn' }, 'Sid': '1', }, ], @@ -283,4 +291,38 @@ export = { expect(stack2).to(haveResource('AWS::SNS::Subscription')); test.done(); }, + + 'fails if topic policy has no actions'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + topic.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + test.done(); + }, + + 'fails if topic policy has no IAM principals'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + topic.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['sns:*'], + })); + + // THEN + test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-sqs/lib/queue-base.ts b/packages/@aws-cdk/aws-sqs/lib/queue-base.ts index 0a5fed37656fd..24d48c4c03f0f 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue-base.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue-base.ts @@ -40,7 +40,7 @@ export interface IQueue extends IResource { * * If this queue was created in this stack (`new Queue`), a queue policy * will be automatically created upon the first call to `addToPolicy`. If - * the queue is improted (`Queue.import`), then this is a no-op. + * the queue is imported (`Queue.import`), then this is a no-op. */ addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult; @@ -139,7 +139,7 @@ export abstract class QueueBase extends Resource implements IQueue { * * If this queue was created in this stack (`new Queue`), a queue policy * will be automatically created upon the first call to `addToPolicy`. If - * the queue is improted (`Queue.import`), then this is a no-op. + * the queue is imported (`Queue.import`), then this is a no-op. */ public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult { if (!this.policy && this.autoCreatePolicy) { @@ -154,6 +154,12 @@ export abstract class QueueBase extends Resource implements IQueue { return { statementAdded: false }; } + protected validate(): string[] { + const errors = super.validate(); + errors.push(...this.policy?.document.validateForResourcePolicy() || []); + return errors; + } + /** * Grant permissions to consume messages from a queue * diff --git a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts index 4e2d09fea3594..46fe8eb633194 100644 --- a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts +++ b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts @@ -1,7 +1,7 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { CfnParameter, Duration, Stack } from '@aws-cdk/core'; +import { CfnParameter, Duration, Stack, App } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as sqs from '../lib'; @@ -410,6 +410,40 @@ export = { test.done(); }, + + 'fails if queue policy has no actions'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const queue = new sqs.Queue(stack, 'Queue'); + + // WHEN + queue.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + test.done(); + }, + + 'fails if queue policy has no IAM principals'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const queue = new sqs.Queue(stack, 'Queue'); + + // WHEN + queue.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['sqs:*'], + })); + + // THEN + test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + test.done(); + }, }; function testGrant(action: (q: sqs.Queue, principal: iam.IPrincipal) => void, ...expectedActions: string[]) { From aad951ae5355391463d9af2a49cd890f8d78f2d0 Mon Sep 17 00:00:00 2001 From: karupanerura Date: Tue, 11 Aug 2020 18:08:38 +0900 Subject: [PATCH 17/43] feat(events): use existing Role when running ECS Task (#8145) Fixes #7859 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-events-targets/lib/ecs-task.ts | 72 ++++++++++++------- .../test/ecs/event-rule-target.test.ts | 52 +++++++++++++- packages/@aws-cdk/aws-events/README.md | 2 +- 3 files changed, 98 insertions(+), 28 deletions(-) diff --git a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts index 4565ee8b9b0f1..77fdae5d37208 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts @@ -61,6 +61,13 @@ export interface EcsTaskProps { * @default A new security group is created */ readonly securityGroups?: ec2.ISecurityGroup[]; + + /** + * Existing IAM role to run the ECS task + * + * @default A new IAM role is created + */ + readonly role?: iam.IRole; } /** @@ -86,6 +93,7 @@ export class EcsTask implements events.IRuleTarget { private readonly cluster: ecs.ICluster; private readonly taskDefinition: ecs.TaskDefinition; private readonly taskCount: number; + private readonly role: iam.IRole; constructor(private readonly props: EcsTaskProps) { if (props.securityGroup !== undefined && props.securityGroups !== undefined) { @@ -96,6 +104,14 @@ export class EcsTask implements events.IRuleTarget { this.taskDefinition = props.taskDefinition; this.taskCount = props.taskCount !== undefined ? props.taskCount : 1; + if (props.role) { + const role = props.role; + this.createEventRolePolicyStatements().forEach(role.addToPolicy.bind(role)); + this.role = role; + } else { + this.role = singletonEventRole(this.taskDefinition, this.createEventRolePolicyStatements()); + } + // Security groups are only configurable with the "awsvpc" network mode. if (this.taskDefinition.networkMode !== ecs.NetworkMode.AWS_VPC) { if (props.securityGroup !== undefined || props.securityGroups !== undefined) { @@ -117,33 +133,8 @@ export class EcsTask implements events.IRuleTarget { * Allows using tasks as target of EventBridge events */ public bind(_rule: events.IRule, _id?: string): events.RuleTargetConfig { - const policyStatements = [new iam.PolicyStatement({ - actions: ['ecs:RunTask'], - resources: [this.taskDefinition.taskDefinitionArn], - conditions: { - ArnEquals: { 'ecs:cluster': this.cluster.clusterArn }, - }, - })]; - - // If it so happens that a Task Execution Role was created for the TaskDefinition, - // then the EventBridge Role must have permissions to pass it (otherwise it doesn't). - if (this.taskDefinition.executionRole !== undefined) { - policyStatements.push(new iam.PolicyStatement({ - actions: ['iam:PassRole'], - resources: [this.taskDefinition.executionRole.roleArn], - })); - } - - // For Fargate task we need permission to pass the task role. - if (this.taskDefinition.isFargateCompatible) { - policyStatements.push(new iam.PolicyStatement({ - actions: ['iam:PassRole'], - resources: [this.taskDefinition.taskRole.roleArn], - })); - } - const arn = this.cluster.clusterArn; - const role = singletonEventRole(this.taskDefinition, policyStatements); + const role = this.role; const containerOverrides = this.props.containerOverrides && this.props.containerOverrides .map(({ containerName, ...overrides }) => ({ name: containerName, ...overrides })); const input = { containerOverrides }; @@ -178,4 +169,33 @@ export class EcsTask implements events.IRuleTarget { targetResource: this.taskDefinition, }; } + + private createEventRolePolicyStatements(): iam.PolicyStatement[] { + const policyStatements = [new iam.PolicyStatement({ + actions: ['ecs:RunTask'], + resources: [this.taskDefinition.taskDefinitionArn], + conditions: { + ArnEquals: { 'ecs:cluster': this.cluster.clusterArn }, + }, + })]; + + // If it so happens that a Task Execution Role was created for the TaskDefinition, + // then the EventBridge Role must have permissions to pass it (otherwise it doesn't). + if (this.taskDefinition.executionRole !== undefined) { + policyStatements.push(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [this.taskDefinition.executionRole.roleArn], + })); + } + + // For Fargate task we need permission to pass the task role. + if (this.taskDefinition.isFargateCompatible) { + policyStatements.push(new iam.PolicyStatement({ + actions: ['iam:PassRole'], + resources: [this.taskDefinition.taskRole.roleArn], + })); + } + + return policyStatements; + } } diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts index 66d7b2aced7fb..a64b7b07d6da3 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts @@ -2,6 +2,7 @@ import '@aws-cdk/assert/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as targets from '../../lib'; @@ -352,4 +353,53 @@ test('uses multiple security groups', () => { }, ], }); -}); \ No newline at end of file +}); + +test('uses existing IAM role', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const role = new iam.Role(stack, 'CustomIamRole', { + assumedBy: new iam.ServicePrincipal('events.amazonaws.com'), + }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + taskDefinition.addContainer('TheContainer', { + image: ecs.ContainerImage.fromRegistry('henk'), + }); + + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); + + // WHEN + rule.addTarget(new targets.EcsTask({ + cluster, + taskDefinition, + taskCount: 1, + containerOverrides: [{ + containerName: 'TheContainer', + command: ['echo', events.EventField.fromPath('$.detail.event')], + }], + role, + })); + + // THEN + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + TaskCount: 1, + TaskDefinitionArn: { + Ref: 'TaskDef54694570', + }, + }, + RoleArn: { 'Fn::GetAtt': ['CustomIamRoleE653F2D1', 'Arn'] }, + Id: 'Target0', + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-events/README.md b/packages/@aws-cdk/aws-events/README.md index 1bc319a0c64b8..cdd45921fff57 100644 --- a/packages/@aws-cdk/aws-events/README.md +++ b/packages/@aws-cdk/aws-events/README.md @@ -89,7 +89,7 @@ import { Rule, Schedule } from '@aws-cdk/aws-events'; import { EcsTask } from '@aws-cdk/aws-events-targets'; ... -const ecsTaskTarget = new EcsTask({ cluster, taskDefinition }); +const ecsTaskTarget = new EcsTask({ cluster, taskDefinition, role }); new Rule(this, 'ScheduleRule', { schedule: Schedule.cron({ minute: '0', hour: '4' }), From b46fdc92d3c3cee269bfa7785fa78679aa781880 Mon Sep 17 00:00:00 2001 From: flemjame-at-amazon <57235867+flemjame-at-amazon@users.noreply.github.com> Date: Tue, 11 Aug 2020 05:31:32 -0400 Subject: [PATCH 18/43] fix(lambda): cannot create lambda in public subnets (#9468) ---- Closes https://github.com/aws/aws-cdk/issues/8935 *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-lambda/lib/function.ts | 19 ++- .../aws-lambda/test/test.vpc-lambda.ts | 119 +++++++++++++++++- 2 files changed, 128 insertions(+), 10 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 92b6d64774751..5d0fd05c00b17 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -299,6 +299,15 @@ export interface FunctionProps extends FunctionOptions { * @default - will not mount any filesystem */ readonly filesystem?: FileSystem; + + /** + * Lambda Functions in a public subnet can NOT access the internet. + * Use this property to acknowledge this limitation and still place the function in a public subnet. + * @see https://stackoverflow.com/questions/52992085/why-cant-an-aws-lambda-function-inside-a-public-subnet-in-a-vpc-connect-to-the/52994841#52994841 + * + * @default false + */ + readonly allowPublicSubnet?: boolean; } /** @@ -819,15 +828,13 @@ export class Function extends FunctionBase { } } - // Pick subnets, make sure they're not Public. Routing through an IGW - // won't work because the ENIs don't get a Public IP. - // Why are we not simply forcing vpcSubnets? Because you might still be choosing - // Isolated networks or selecting among 2 sets of Private subnets by name. + const allowPublicSubnet = props.allowPublicSubnet ?? false; const { subnetIds } = props.vpc.selectSubnets(props.vpcSubnets); const publicSubnetIds = new Set(props.vpc.publicSubnets.map(s => s.subnetId)); for (const subnetId of subnetIds) { - if (publicSubnetIds.has(subnetId)) { - throw new Error('Not possible to place Lambda Functions in a Public subnet'); + if (publicSubnetIds.has(subnetId) && !allowPublicSubnet) { + throw new Error('Lambda Functions in a public subnet can NOT access the internet. ' + + 'If you are aware of this limitation and would still like to place the function int a public subnet, set `allowPublicSubnet` to true'); } } diff --git a/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts b/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts index a3633400b4ccb..6e4f47de11c57 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts @@ -212,22 +212,133 @@ export = { test.done(); }, - 'picking public subnets is not allowed'(test: Test) { + 'can pick public subnet for Lambda'(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); + // WHEN + new lambda.Function(stack, 'PublicLambda', { + allowPublicSubnet: true, + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + }); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::Function', { + VpcConfig: { + SecurityGroupIds: [ + {'Fn::GetAtt': [ 'PublicLambdaSecurityGroup61D896FD', 'GroupId' ]}, + ], + SubnetIds: [ + {Ref: 'VPCPublicSubnet1SubnetB4246D30'}, + {Ref: 'VPCPublicSubnet2Subnet74179F39'}, + ], + }, + })); + test.done(); + }, + + 'can pick private subnet for Lambda'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new lambda.Function(stack, 'PrivateLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE }, + }); + + // THEN + + expect(stack).to(haveResource('AWS::Lambda::Function', { + VpcConfig: { + SecurityGroupIds: [ + {'Fn::GetAtt': [ 'PrivateLambdaSecurityGroupF53C8342', 'GroupId' ]}, + ], + SubnetIds: [ + {Ref: 'VPCPrivateSubnet1Subnet8BCA10E0'}, + {Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A'}, + ], + }, + })); + test.done(); + }, + + 'can pick isolated subnet for Lambda'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { + subnetConfiguration: [ + { + name: 'Isolated', + subnetType: ec2.SubnetType.ISOLATED, + }, + ], + }); + + // WHEN + new lambda.Function(stack, 'IsolatedLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.ISOLATED }, + }); + + // THEN + + expect(stack).to(haveResource('AWS::Lambda::Function', { + VpcConfig: { + SecurityGroupIds: [ + {'Fn::GetAtt': [ 'IsolatedLambdaSecurityGroupCE25B6A9', 'GroupId' ]}, + ], + SubnetIds: [ + {Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6'}, + {Ref: 'VPCIsolatedSubnet2Subnet4B1C8CAA'}, + ], + }, + })); + test.done(); + }, + + 'picking public subnet type is not allowed if not overriding allowPublicSubnet'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { + subnetConfiguration: [ + { + name: 'Public', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + name: 'Private', + subnetType: ec2.SubnetType.PRIVATE, + }, + { + name: 'Isolated', + subnetType: ec2.SubnetType.ISOLATED, + }, + ], + }); + // WHEN test.throws(() => { - new lambda.Function(stack, 'Lambda', { + new lambda.Function(stack, 'PublicLambda', { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_10_X, vpc, vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, }); - }); - + }, /Lambda Functions in a public subnet/); test.done(); }, }; From 6a8cba4e908e6f6179d37bce9e5c345bd7fc89f6 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 11 Aug 2020 12:53:24 +0300 Subject: [PATCH 19/43] chore: use "construct" instead of "node" across the library (#9584) As a follow-up for #9557, replace all usage of the deprecated `node` API with `construct`. Related: https://github.com/aws/aws-cdk-rfcs/issues/192 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/pipeline-deploy-stack-action.ts | 2 +- .../test/test.pipeline-deploy-stack-action.ts | 2 +- packages/@aws-cdk/assert/lib/synth-utils.ts | 2 +- packages/@aws-cdk/assets/test/test.staging.ts | 2 +- packages/@aws-cdk/aws-amplify/lib/app.ts | 2 +- .../aws-apigateway/lib/authorizers/lambda.ts | 10 ++++---- .../@aws-cdk/aws-apigateway/lib/deployment.ts | 6 ++--- .../aws-apigateway/lib/domain-name.ts | 2 +- .../aws-apigateway/lib/gateway-response.ts | 2 +- .../aws-apigateway/lib/integrations/lambda.ts | 4 ++-- .../@aws-cdk/aws-apigateway/lib/method.ts | 2 +- packages/@aws-cdk/aws-apigateway/lib/model.ts | 2 +- .../aws-apigateway/lib/requestvalidator.ts | 2 +- .../@aws-cdk/aws-apigateway/lib/resource.ts | 4 ++-- .../@aws-cdk/aws-apigateway/lib/restapi.ts | 6 ++--- .../@aws-cdk/aws-apigateway/lib/usage-plan.ts | 2 +- .../@aws-cdk/aws-apigateway/lib/vpc-link.ts | 2 +- .../test/integ.restapi-import.lit.ts | 2 +- .../aws-apigateway/test/test.deployment.ts | 2 +- .../aws-apigateway/test/test.method.ts | 8 +++---- .../aws-apigateway/test/test.model.ts | 4 ++-- .../test/test.requestvalidator.ts | 4 ++-- .../aws-apigateway/test/test.restapi.ts | 10 ++++---- .../aws-apigatewayv2/lib/http/api-mapping.ts | 4 ++-- .../@aws-cdk/aws-apigatewayv2/lib/http/api.ts | 2 +- .../lib/http/integrations/lambda.ts | 2 +- .../aws-apigatewayv2/lib/http/route.ts | 2 +- .../aws-apigatewayv2/lib/http/stage.ts | 2 +- .../lib/step-scaling-action.ts | 2 +- .../lib/target-tracking-scaling-policy.ts | 2 +- packages/@aws-cdk/aws-appmesh/lib/mesh.ts | 2 +- packages/@aws-cdk/aws-appmesh/lib/route.ts | 2 +- .../@aws-cdk/aws-appmesh/lib/virtual-node.ts | 2 +- .../aws-appmesh/lib/virtual-router.ts | 2 +- .../aws-appmesh/lib/virtual-service.ts | 2 +- .../aws-autoscaling/lib/auto-scaling-group.ts | 12 +++++----- .../aws-autoscaling/lib/lifecycle-hook.ts | 2 +- .../test/auto-scaling-group.test.ts | 14 +++++------ packages/@aws-cdk/aws-backup/lib/plan.ts | 2 +- packages/@aws-cdk/aws-backup/lib/selection.ts | 4 ++-- packages/@aws-cdk/aws-backup/lib/vault.ts | 2 +- .../aws-batch/lib/compute-environment.ts | 2 +- .../test/compute-environment.test.ts | 4 ++-- .../aws-certificatemanager/lib/util.ts | 2 +- .../aws-cloudformation/test/test.deps.ts | 2 +- .../test/test.nested-stack.ts | 4 ++-- .../aws-cloudfront/lib/distribution.ts | 4 ++-- .../aws-cloudfront/lib/web_distribution.ts | 2 +- .../test/web_distribution.test.ts | 2 +- .../@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts | 4 ++-- .../aws-cloudwatch/lib/composite-alarm.ts | 2 +- .../@aws-cdk/aws-codebuild/lib/project.ts | 4 ++-- .../@aws-cdk/aws-codecommit/lib/repository.ts | 2 +- .../lib/lambda/deployment-group.ts | 2 +- .../lib/profiling-group.ts | 2 +- .../lib/cloudformation/pipeline-actions.ts | 4 ++-- .../lib/codecommit/source-action.ts | 2 +- .../lib/ecr/source-action.ts | 2 +- .../lib/s3/source-action.ts | 4 ++-- .../test.cloudformation-pipeline-actions.ts | 2 +- .../test/test.pipeline.ts | 4 ++-- .../@aws-cdk/aws-codepipeline/lib/pipeline.ts | 14 +++++------ .../aws-codepipeline/test/test.pipeline.ts | 2 +- .../@aws-cdk/aws-cognito/lib/user-pool.ts | 2 +- packages/@aws-cdk/aws-config/lib/rule.ts | 2 +- packages/@aws-cdk/aws-docdb/lib/cluster.ts | 6 ++--- .../@aws-cdk/aws-docdb/test/cluster.test.ts | 2 +- .../@aws-cdk/aws-docdb/test/instance.test.ts | 2 +- .../lib/aws-dynamodb-global.ts | 2 +- .../test/test.dynamodb.global.ts | 6 ++--- .../aws-dynamodb/lib/replica-provider.ts | 2 +- packages/@aws-cdk/aws-dynamodb/lib/table.ts | 18 +++++++------- .../aws-dynamodb/test/dynamodb.test.ts | 8 +++---- .../test/integ.dynamodb.ondemand.ts | 2 +- .../aws-dynamodb/test/integ.dynamodb.sse.ts | 2 +- .../aws-dynamodb/test/integ.dynamodb.ts | 2 +- packages/@aws-cdk/aws-ec2/lib/instance.ts | 10 ++++---- .../@aws-cdk/aws-ec2/lib/security-group.ts | 10 ++++---- packages/@aws-cdk/aws-ec2/lib/user-data.ts | 4 ++-- packages/@aws-cdk/aws-ec2/lib/util.ts | 2 +- packages/@aws-cdk/aws-ec2/lib/volume.ts | 4 ++-- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 24 +++++++++---------- .../@aws-cdk/aws-ec2/test/instance.test.ts | 8 +++---- .../aws-ec2/test/vpc-endpoint.test.ts | 10 ++++---- packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 12 +++++----- .../aws-ecr-assets/lib/image-asset.ts | 2 +- .../aws-ecr-assets/test/test.image-asset.ts | 6 ++--- .../application-load-balanced-service-base.ts | 4 ++-- ...ion-multiple-target-groups-service-base.ts | 14 +++++------ .../network-load-balanced-service-base.ts | 4 ++-- ...ork-multiple-target-groups-service-base.ts | 12 +++++----- .../lib/base/queue-processing-service-base.ts | 6 ++--- .../lib/base/scheduled-task-base.ts | 4 ++-- .../application-load-balanced-ecs-service.ts | 2 +- .../ecs/network-load-balanced-ecs-service.ts | 2 +- .../lib/ecs/scheduled-ecs-task.ts | 2 +- ...plication-load-balanced-fargate-service.ts | 2 +- .../network-load-balanced-fargate-service.ts | 2 +- .../lib/fargate/scheduled-fargate-task.ts | 2 +- .../aws-ecs-patterns/test/ec2/test.l3s-v2.ts | 12 +++++----- .../@aws-cdk/aws-ecs/lib/base/base-service.ts | 4 ++-- .../aws-ecs/lib/base/task-definition.ts | 2 +- .../aws-ecs/lib/container-definition.ts | 4 ++-- .../@aws-cdk/aws-ecs/lib/images/repository.ts | 2 +- .../aws-ecs/test/ec2/test.ec2-service.ts | 2 +- .../test/ec2/test.ec2-task-definition.ts | 4 ++-- .../test/fargate/test.fargate-service.ts | 2 +- .../@aws-cdk/aws-efs/lib/efs-file-system.ts | 2 +- .../aws-efs/test/efs-file-system.test.ts | 2 +- .../@aws-cdk/aws-eks-legacy/lib/cluster.ts | 6 ++--- .../@aws-cdk/aws-eks-legacy/lib/helm-chart.ts | 4 ++-- .../aws-eks-legacy/lib/kubectl-layer.ts | 4 ++-- .../@aws-cdk/aws-eks-legacy/lib/user-data.ts | 2 +- .../aws-eks/lib/cluster-resource-provider.ts | 2 +- .../@aws-cdk/aws-eks/lib/cluster-resource.ts | 2 +- packages/@aws-cdk/aws-eks/lib/cluster.ts | 14 +++++------ .../@aws-cdk/aws-eks/lib/fargate-profile.ts | 2 +- packages/@aws-cdk/aws-eks/lib/helm-chart.ts | 2 +- .../@aws-cdk/aws-eks/lib/kubectl-layer.ts | 4 ++-- .../@aws-cdk/aws-eks/lib/legacy-cluster.ts | 4 ++-- .../@aws-cdk/aws-eks/lib/service-account.ts | 2 +- packages/@aws-cdk/aws-eks/lib/user-data.ts | 2 +- .../aws-eks/test/integ.eks-cluster.ts | 2 +- .../@aws-cdk/aws-eks/test/test.cluster.ts | 14 +++++------ .../lib/load-balancer.ts | 2 +- .../test/test.loadbalancer.ts | 2 +- .../test/integ.cognito.lit.ts | 2 +- .../lib/alb/application-listener-rule.ts | 2 +- .../lib/alb/application-load-balancer.ts | 6 ++--- .../lib/alb/application-target-group.ts | 4 ++-- .../lib/nlb/network-load-balancer.ts | 4 ++-- .../lib/shared/base-listener.ts | 2 +- .../lib/shared/base-load-balancer.ts | 4 ++-- .../lib/shared/base-target-group.ts | 2 +- .../test/alb/test.listener.ts | 2 +- .../test/integ.alb.dualstack.ts | 4 ++-- .../test/integ.nlb.ts | 2 +- .../test/nlb/test.listener.ts | 2 +- .../aws-events-targets/lib/aws-api.ts | 2 +- .../@aws-cdk/aws-events-targets/lib/batch.ts | 2 +- .../aws-events-targets/lib/ecs-task.ts | 4 ++-- .../@aws-cdk/aws-events-targets/lib/util.ts | 4 ++-- .../test/codepipeline/pipeline.test.ts | 2 +- packages/@aws-cdk/aws-events/lib/event-bus.ts | 2 +- packages/@aws-cdk/aws-events/lib/rule.ts | 8 +++---- .../@aws-cdk/aws-events/test/test.rule.ts | 6 ++--- packages/@aws-cdk/aws-glue/lib/table.ts | 2 +- packages/@aws-cdk/aws-glue/test/table.test.ts | 4 ++-- packages/@aws-cdk/aws-iam/lib/grant.ts | 4 ++-- packages/@aws-cdk/aws-iam/lib/role.ts | 2 +- .../@aws-cdk/aws-iam/lib/unknown-principal.ts | 4 ++-- .../aws-iam/test/escape-hatch.test.ts | 6 ++--- packages/@aws-cdk/aws-iam/test/policy.test.ts | 6 ++--- .../aws-iam/test/role.from-role-arn.test.ts | 2 +- packages/@aws-cdk/aws-kinesis/lib/stream.ts | 4 ++-- packages/@aws-cdk/aws-kms/test/test.key.ts | 6 ++--- .../aws-lambda-event-sources/lib/api.ts | 4 ++-- .../aws-lambda-event-sources/lib/dynamodb.ts | 4 ++-- .../aws-lambda-event-sources/lib/kinesis.ts | 2 +- .../aws-lambda-event-sources/lib/sqs.ts | 2 +- .../@aws-cdk/aws-lambda/lib/function-base.ts | 8 +++---- .../@aws-cdk/aws-lambda/lib/function-hash.ts | 2 +- packages/@aws-cdk/aws-lambda/lib/function.ts | 10 ++++---- .../aws-lambda/lib/singleton-lambda.ts | 6 ++--- .../@aws-cdk/aws-lambda/test/test.code.ts | 2 +- .../@aws-cdk/aws-lambda/test/test.layers.ts | 2 +- .../aws-logs-destinations/lib/kinesis.ts | 2 +- packages/@aws-cdk/aws-rds/lib/cluster.ts | 6 ++--- packages/@aws-cdk/aws-rds/lib/instance.ts | 6 ++--- packages/@aws-cdk/aws-rds/lib/proxy.ts | 4 ++-- .../@aws-cdk/aws-rds/test/test.cluster.ts | 2 +- packages/@aws-cdk/aws-redshift/lib/cluster.ts | 2 +- .../aws-redshift/test/cluster.test.ts | 2 +- .../lib/cloudfront-target.ts | 2 +- .../lib/interface-vpc-endpoint-target.ts | 2 +- .../test/test.hosted-zone-provider.ts | 4 ++-- packages/@aws-cdk/aws-s3-assets/lib/asset.ts | 2 +- .../@aws-cdk/aws-s3-assets/test/asset.test.ts | 6 ++--- .../@aws-cdk/aws-s3-deployment/lib/source.ts | 2 +- .../aws-s3-notifications/lib/lambda.ts | 2 +- .../test/notifications.test.ts | 2 +- packages/@aws-cdk/aws-s3/lib/bucket.ts | 4 ++-- .../notifications-resource-handler.ts | 4 ++-- .../notifications-resource.ts | 2 +- packages/@aws-cdk/aws-s3/test/test.aspect.ts | 6 ++--- .../aws-secretsmanager/lib/secret-rotation.ts | 2 +- .../@aws-cdk/aws-secretsmanager/lib/secret.ts | 2 +- .../lib/alias-target-instance.ts | 2 +- .../aws-servicediscovery/lib/instance.ts | 2 +- .../@aws-cdk/aws-ses-actions/lib/lambda.ts | 4 ++-- packages/@aws-cdk/aws-ses-actions/lib/s3.ts | 6 ++--- .../aws-sns-subscriptions/lib/lambda.ts | 4 ++-- .../@aws-cdk/aws-sns-subscriptions/lib/sqs.ts | 2 +- packages/@aws-cdk/aws-sns/lib/topic-base.ts | 8 +++---- packages/@aws-cdk/aws-sqs/lib/queue.ts | 2 +- packages/@aws-cdk/aws-ssm/lib/parameter.ts | 4 ++-- .../aws-ssm/test/integ.parameter-arns.ts | 2 +- .../lib/ecs/run-ecs-task-base.ts | 2 +- .../lib/ecs/run-task.ts | 2 +- .../aws-stepfunctions/lib/activity.ts | 2 +- .../lib/state-machine-fragment.ts | 2 +- .../aws-stepfunctions/lib/state-machine.ts | 2 +- .../aws-stepfunctions/lib/states/state.ts | 4 ++-- .../test/valid-templates.test.ts | 4 ++-- packages/@aws-cdk/core/lib/annotations.ts | 2 +- packages/@aws-cdk/core/lib/aspect.ts | 4 ++-- .../@aws-cdk/core/lib/construct-compat.ts | 4 ++-- .../core/lib/private/tree-metadata.ts | 2 +- .../lib/provider-framework/provider.ts | 2 +- .../waiter-state-machine.ts | 2 +- .../integ.aws-custom-resource.ts | 2 +- .../test/provider-framework/integ.provider.ts | 2 +- .../integration-test-fixtures/s3-assert.ts | 2 +- .../integration-test-fixtures/s3-file.ts | 2 +- .../lib/actions/deploy-cdk-stack-action.ts | 4 ++-- packages/@aws-cdk/pipelines/lib/pipeline.ts | 6 ++--- .../lib/private/construct-internals.ts | 4 ++-- packages/@aws-cdk/pipelines/lib/stage.ts | 2 +- .../test/cross-environment-infra.test.ts | 2 +- packages/decdk/lib/declarative-stack.ts | 8 +++---- 220 files changed, 423 insertions(+), 423 deletions(-) diff --git a/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts index 03685cfc9c413..7f22106e844f7 100644 --- a/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts @@ -115,7 +115,7 @@ export class PipelineDeployStackAction implements codepipeline.IAction { constructor(props: PipelineDeployStackActionProps) { this.stack = props.stack; - const assets = this.stack.node.metadata.filter(md => md.type === cxschema.ArtifactMetadataEntryType.ASSET); + const assets = this.stack.construct.metadata.filter(md => md.type === cxschema.ArtifactMetadataEntryType.ASSET); if (assets.length > 0) { // FIXME: Implement the necessary actions to publish assets throw new Error(`Cannot deploy the stack ${this.stack.stackName} because it references ${assets.length} asset(s)`); diff --git a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts index 918279b480b30..641e12331fdbc 100644 --- a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts @@ -390,7 +390,7 @@ export = nodeunit.testCase({ const deployedStack = new cdk.Stack(app, 'DeployedStack'); for (let i = 0 ; i < assetCount ; i++) { - deployedStack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, {}); + deployedStack.construct.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, {}); } test.throws(() => { diff --git a/packages/@aws-cdk/assert/lib/synth-utils.ts b/packages/@aws-cdk/assert/lib/synth-utils.ts index bb8d9a437afd9..dfd73b371dd65 100644 --- a/packages/@aws-cdk/assert/lib/synth-utils.ts +++ b/packages/@aws-cdk/assert/lib/synth-utils.ts @@ -65,7 +65,7 @@ export class SynthUtils { * Synthesizes the app in which a stack resides and returns the cloud assembly object. */ function synthesizeApp(stack: core.Stack, options: core.SynthesisOptions) { - const root = stack.node.root; + const root = stack.construct.root; if (!core.Stage.isStage(root)) { throw new Error('unexpected: all stacks must be part of a Stage or an App'); } diff --git a/packages/@aws-cdk/assets/test/test.staging.ts b/packages/@aws-cdk/assets/test/test.staging.ts index a6841284e8731..2b155c75108af 100644 --- a/packages/@aws-cdk/assets/test/test.staging.ts +++ b/packages/@aws-cdk/assets/test/test.staging.ts @@ -23,7 +23,7 @@ export = { 'staging can be disabled through context'(test: Test) { // GIVEN const stack = new Stack(); - stack.node.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); + stack.construct.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); const sourcePath = path.join(__dirname, 'fs', 'fixtures', 'test1'); // WHEN diff --git a/packages/@aws-cdk/aws-amplify/lib/app.ts b/packages/@aws-cdk/aws-amplify/lib/app.ts index 1d41c0e07ede3..e18917afae9b2 100644 --- a/packages/@aws-cdk/aws-amplify/lib/app.ts +++ b/packages/@aws-cdk/aws-amplify/lib/app.ts @@ -221,7 +221,7 @@ export class App extends Resource implements IApp, iam.IGrantable { description: props.description, environmentVariables: Lazy.anyValue({ produce: () => renderEnvironmentVariables(this.environmentVariables) }, { omitEmptyArray: true }), iamServiceRole: role.roleArn, - name: props.appName || this.node.id, + name: props.appName || this.construct.id, oauthToken: sourceCodeProviderOptions?.oauthToken?.toString(), repository: sourceCodeProviderOptions?.repository, }); diff --git a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts index f79d675af1e7f..002a1e71aa157 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts @@ -12,7 +12,7 @@ export interface LambdaAuthorizerProps { /** * An optional human friendly name for the authorizer. Note that, this is not the primary identifier of the authorizer. * - * @default this.node.uniqueId + * @default this.construct.uniqueId */ readonly authorizerName?: string; @@ -96,7 +96,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer { */ protected setupPermissions() { if (!this.role) { - this.handler.addPermission(`${this.node.uniqueId}:Permissions`, { + this.handler.addPermission(`${this.construct.uniqueId}:Permissions`, { principal: new iam.ServicePrincipal('apigateway.amazonaws.com'), sourceArn: this.authorizerArn, }); @@ -120,7 +120,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer { return Lazy.stringValue({ produce: () => { if (!this.restApiId) { - throw new Error(`Authorizer (${this.node.path}) must be attached to a RestApi`); + throw new Error(`Authorizer (${this.construct.path}) must be attached to a RestApi`); } return this.restApiId; }, @@ -167,7 +167,7 @@ export class TokenAuthorizer extends LambdaAuthorizer { const restApiId = this.lazyRestApiId(); const resource = new CfnAuthorizer(this, 'Resource', { - name: props.authorizerName ?? this.node.uniqueId, + name: props.authorizerName ?? this.construct.uniqueId, restApiId, type: 'TOKEN', authorizerUri: lambdaAuthorizerArn(props.handler), @@ -229,7 +229,7 @@ export class RequestAuthorizer extends LambdaAuthorizer { const restApiId = this.lazyRestApiId(); const resource = new CfnAuthorizer(this, 'Resource', { - name: props.authorizerName ?? this.node.uniqueId, + name: props.authorizerName ?? this.construct.uniqueId, restApiId, type: 'REQUEST', authorizerUri: lambdaAuthorizerArn(props.handler), diff --git a/packages/@aws-cdk/aws-apigateway/lib/deployment.ts b/packages/@aws-cdk/aws-apigateway/lib/deployment.ts index 404ba1855bd68..799d6f9ccee72 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/deployment.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/deployment.ts @@ -118,7 +118,7 @@ export class Deployment extends Resource { // and the `AWS::Lambda::Permission` resources (children under Method), // causing cyclic dependency errors. Hence, falling back to declaring // dependencies between the underlying CfnResources. - this.node.addDependency(method.node.defaultChild as CfnResource); + this.construct.addDependency(method.construct.defaultChild as CfnResource); } } @@ -150,7 +150,7 @@ class LatestDeploymentResource extends CfnDeployment { public addToLogicalId(data: unknown) { // if the construct is locked, it means we are already synthesizing and then // we can't modify the hash because we might have already calculated it. - if (this.node.locked) { + if (this.construct.locked) { throw new Error('Cannot modify the logical ID when the construct is locked'); } @@ -163,7 +163,7 @@ class LatestDeploymentResource extends CfnDeployment { if (this.api instanceof RestApi || this.api instanceof SpecRestApi) { // Ignore IRestApi that are imported // Add CfnRestApi to the logical id so a new deployment is triggered when any of its properties change. - const cfnRestApiCF = (this.api.node.defaultChild as any)._toCloudFormation(); + const cfnRestApiCF = (this.api.construct.defaultChild as any)._toCloudFormation(); hash.push(this.stack.resolve(cfnRestApiCF)); } diff --git a/packages/@aws-cdk/aws-apigateway/lib/domain-name.ts b/packages/@aws-cdk/aws-apigateway/lib/domain-name.ts index f44ebf953dcac..5c85e3415354f 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/domain-name.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/domain-name.ts @@ -137,7 +137,7 @@ export class DomainName extends Resource implements IDomainName { */ public addBasePathMapping(targetApi: IRestApi, options: BasePathMappingOptions = { }) { const basePath = options.basePath || '/'; - const id = `Map:${basePath}=>${targetApi.node.uniqueId}`; + const id = `Map:${basePath}=>${targetApi.construct.uniqueId}`; return new BasePathMapping(this, id, { domainName: this, restApi: targetApi, diff --git a/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts b/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts index 62957167fa881..35d02d7c15e27 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts @@ -65,7 +65,7 @@ export class GatewayResponse extends Resource implements IGatewayResponse { statusCode: props.statusCode, }); - this.node.defaultChild = resource; + this.construct.defaultChild = resource; } private buildResponseParameters(responseHeaders?: { [key: string]: string }): { [key: string]: string } | undefined { diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts index c6a8ec04863c7..7d6ec4c2530ac 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts @@ -56,7 +56,7 @@ export class LambdaIntegration extends AwsIntegration { const bindResult = super.bind(method); const principal = new iam.ServicePrincipal('apigateway.amazonaws.com'); - const desc = `${method.api.node.uniqueId}.${method.httpMethod}.${method.resource.path.replace(/\//g, '.')}`; + const desc = `${method.api.construct.uniqueId}.${method.httpMethod}.${method.resource.path.replace(/\//g, '.')}`; this.handler.addPermission(`ApiPermission.${desc}`, { principal, @@ -78,7 +78,7 @@ export class LambdaIntegration extends AwsIntegration { if (this.handler instanceof lambda.Function) { // if not imported, extract the name from the CFN layer to reach // the literal value if it is given (rather than a token) - functionName = (this.handler.node.defaultChild as lambda.CfnFunction).functionName; + functionName = (this.handler.construct.defaultChild as lambda.CfnFunction).functionName; } else { // imported, just take the function name. functionName = this.handler.functionName; diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index 172eb77cd1877..586d0f2258a66 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -221,7 +221,7 @@ export class Method extends Resource { const deployment = props.resource.api.latestDeployment; if (deployment) { - deployment.node.addDependency(resource); + deployment.construct.addDependency(resource); deployment.addToLogicalId({ method: { ...methodProps, diff --git a/packages/@aws-cdk/aws-apigateway/lib/model.ts b/packages/@aws-cdk/aws-apigateway/lib/model.ts index 088dee9b98750..df0aa0b5d9718 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/model.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/model.ts @@ -178,7 +178,7 @@ export class Model extends Resource implements IModel { const deployment = (props.restApi instanceof RestApi) ? props.restApi.latestDeployment : undefined; if (deployment) { - deployment.node.addDependency(resource); + deployment.construct.addDependency(resource); deployment.addToLogicalId({ model: modelProps }); } } diff --git a/packages/@aws-cdk/aws-apigateway/lib/requestvalidator.ts b/packages/@aws-cdk/aws-apigateway/lib/requestvalidator.ts index ce56903f79a0d..b31155bf5c941 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/requestvalidator.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/requestvalidator.ts @@ -81,7 +81,7 @@ export class RequestValidator extends Resource implements IRequestValidator { const deployment = (props.restApi instanceof RestApi) ? props.restApi.latestDeployment : undefined; if (deployment) { - deployment.node.addDependency(resource); + deployment.construct.addDependency(resource); deployment.addToLogicalId({ validator: validatorProps }); } } diff --git a/packages/@aws-cdk/aws-apigateway/lib/resource.ts b/packages/@aws-cdk/aws-apigateway/lib/resource.ts index 102a17a5cdc27..003c4b0575ba5 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/resource.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/resource.ts @@ -410,7 +410,7 @@ export class Resource extends ResourceBase { const deployment = props.parent.api.latestDeployment; if (deployment) { - deployment.node.addDependency(resource); + deployment.construct.addDependency(resource); deployment.addToLogicalId({ resource: resourceProps }); } @@ -488,7 +488,7 @@ export class ProxyResource extends Resource { // the root so that empty paths are proxied as well. if (this.parentResource && this.parentResource.path === '/') { // skip if the root resource already has this method defined - if (!(this.parentResource.node.tryFindChild(httpMethod) instanceof Method)) { + if (!(this.parentResource.construct.tryFindChild(httpMethod) instanceof Method)) { this.parentResource.addMethod(httpMethod, integration, options); } } diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index f027a2f7424be..606bf536fbbf4 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -401,7 +401,7 @@ export abstract class RestApiBase extends Resource implements IRestApi { cloudWatchRoleArn: role.roleArn, }); - resource.node.addDependency(apiResource); + resource.construct.addDependency(apiResource); } protected configureDeployment(props: RestApiOptions) { @@ -492,7 +492,7 @@ export class SpecRestApi extends RestApiBase { endpointConfiguration: this._configureEndpoints(props), parameters: props.parameters, }); - this.node.defaultChild = resource; + this.construct.defaultChild = resource; this.restApiId = resource.ref; this.restApiRootResourceId = resource.attrRootResourceId; this.root = new RootResource(this, {}, this.restApiRootResourceId); @@ -597,7 +597,7 @@ export class RestApi extends RestApiBase { cloneFrom: props.cloneFrom ? props.cloneFrom.restApiId : undefined, parameters: props.parameters, }); - this.node.defaultChild = resource; + this.construct.defaultChild = resource; this.restApiId = resource.ref; const cloudWatchRole = props.cloudWatchRole !== undefined ? props.cloudWatchRole : true; diff --git a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts index c6029c5840e4c..c25c744fa65ec 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts @@ -181,7 +181,7 @@ export class UsagePlan extends Resource { const prefix = 'UsagePlanKeyResource'; // Postfixing apikey id only from the 2nd child, to keep physicalIds of UsagePlanKey for existing CDK apps unmodifed. - const id = this.node.tryFindChild(prefix) ? `${prefix}:${apiKey.node.uniqueId}` : prefix; + const id = this.construct.tryFindChild(prefix) ? `${prefix}:${apiKey.construct.uniqueId}` : prefix; new CfnUsagePlanKey(this, id, { keyId: apiKey.keyId, diff --git a/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts b/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts index 81f6f843b97df..2cc66b0f8885c 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts @@ -65,7 +65,7 @@ export class VpcLink extends Resource implements IVpcLink { constructor(scope: Construct, id: string, props: VpcLinkProps = {}) { super(scope, id, { physicalName: props.vpcLinkName || - Lazy.stringValue({ produce: () => this.node.uniqueId }), + Lazy.stringValue({ produce: () => this.construct.uniqueId }), }); const cfnResource = new CfnVpcLink(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts index bea2be6c5b05f..60017e092f340 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts @@ -116,7 +116,7 @@ class DeployStack extends NestedStack { const deployment = new Deployment(this, 'Deployment', { api: RestApi.fromRestApiId(this, 'RestApi', props.restApiId), }); - (props.methods ?? []).forEach((method) => deployment.node.addDependency(method)); + (props.methods ?? []).forEach((method) => deployment.construct.addDependency(method)); new Stage(this, 'Stage', { deployment }); } } diff --git a/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts b/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts index 0f5ce4a37732d..ebacaac1973c2 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts @@ -178,7 +178,7 @@ export = { const dep = new CfnResource(stack, 'MyResource', { type: 'foo' }); // WHEN - deployment.node.addDependency(dep); + deployment.construct.addDependency(dep); expect(stack).to(haveResource('AWS::ApiGateway::Deployment', { DependsOn: [ diff --git a/packages/@aws-cdk/aws-apigateway/test/test.method.ts b/packages/@aws-cdk/aws-apigateway/test/test.method.ts index 85111b4636882..b4a94b20bf44c 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.method.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.method.ts @@ -474,7 +474,7 @@ export = { expect(stack).to(haveResource('AWS::ApiGateway::Method', { HttpMethod: 'GET', RequestModels: { - 'application/json': { Ref: stack.getLogicalId(model.node.findChild('Resource') as cdk.CfnElement) }, + 'application/json': { Ref: stack.getLogicalId(model.construct.findChild('Resource') as cdk.CfnElement) }, }, })); @@ -539,7 +539,7 @@ export = { ResponseModels: { 'application/json': 'Empty', 'text/plain': 'Error', - 'text/html': { Ref: stack.getLogicalId(htmlModel.node.findChild('Resource') as cdk.CfnElement) }, + 'text/html': { Ref: stack.getLogicalId(htmlModel.construct.findChild('Resource') as cdk.CfnElement) }, }, }, ], @@ -568,10 +568,10 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::Method', { - RequestValidatorId: { Ref: stack.getLogicalId(validator.node.findChild('Resource') as cdk.CfnElement) }, + RequestValidatorId: { Ref: stack.getLogicalId(validator.construct.findChild('Resource') as cdk.CfnElement) }, })); expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, ValidateRequestBody: true, ValidateRequestParameters: false, })); diff --git a/packages/@aws-cdk/aws-apigateway/test/test.model.ts b/packages/@aws-cdk/aws-apigateway/test/test.model.ts index 9f0907b1e66f2..a6f4e5fa393fd 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.model.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.model.ts @@ -26,7 +26,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::Model', { - RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, Schema: { $schema: 'http://json-schema.org/draft-04/schema#', title: 'test', @@ -61,7 +61,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::Model', { - RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, Schema: { $schema: 'http://json-schema.org/draft-04/schema#', title: 'test', diff --git a/packages/@aws-cdk/aws-apigateway/test/test.requestvalidator.ts b/packages/@aws-cdk/aws-apigateway/test/test.requestvalidator.ts index b264f85c0733c..f7b9e89d65632 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.requestvalidator.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.requestvalidator.ts @@ -22,7 +22,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, ValidateRequestBody: true, ValidateRequestParameters: false, })); @@ -49,7 +49,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, Name: 'my-model', ValidateRequestBody: false, ValidateRequestParameters: true, diff --git a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts index 9736dc2e188b5..4ae50a9910065 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts @@ -103,7 +103,7 @@ export = { 'defaultChild is set correctly'(test: Test) { const stack = new Stack(); const api = new apigw.RestApi(stack, 'my-api'); - test.ok(api.node.defaultChild instanceof apigw.CfnRestApi); + test.ok(api.construct.defaultChild instanceof apigw.CfnRestApi); test.done(); }, @@ -570,7 +570,7 @@ export = { const resource = new CfnResource(stack, 'DependsOnRestApi', { type: 'My::Resource' }); // WHEN - resource.node.addDependency(api); + resource.construct.addDependency(api); // THEN expect(stack).to(haveResource('My::Resource', { @@ -713,7 +713,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::Model', { - RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as CfnElement) }, Schema: { $schema: 'http://json-schema.org/draft-04/schema#', title: 'test', @@ -745,14 +745,14 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as CfnElement) }, Name: 'Parameters', ValidateRequestBody: false, ValidateRequestParameters: true, })); expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as CfnElement) }, Name: 'Body', ValidateRequestBody: true, ValidateRequestParameters: false, diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api-mapping.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api-mapping.ts index 17461f258b288..cc35eeb466ace 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api-mapping.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api-mapping.ts @@ -93,12 +93,12 @@ export class HttpApiMapping extends Resource implements IApiMapping { // ensure the dependency on the provided stage if (props.stage) { - this.node.addDependency(props.stage); + this.construct.addDependency(props.stage); } // if stage not specified, we ensure the default stage is ready before we create the api mapping if (!props.stage?.stageName && props.api.defaultStage) { - this.node.addDependency(props.api.defaultStage!); + this.construct.addDependency(props.api.defaultStage!); } this.apiMappingId = resource.ref; diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index d868b25f9eea1..56931abf0b37e 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -191,7 +191,7 @@ export class HttpApi extends Resource implements IHttpApi { // to ensure the domain is ready before creating the default stage if(props?.defaultDomainMapping) { - this.defaultStage.node.addDependency(props.defaultDomainMapping.domainName); + this.defaultStage.construct.addDependency(props.defaultDomainMapping.domainName); } } diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integrations/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integrations/lambda.ts index 30973a10b2ca0..fe656e0a03947 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integrations/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integrations/lambda.ts @@ -30,7 +30,7 @@ export class LambdaProxyIntegration implements IHttpRouteIntegration { public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { const route = options.route; - this.props.handler.addPermission(`${route.node.uniqueId}-Permission`, { + this.props.handler.addPermission(`${route.construct.uniqueId}-Permission`, { scope: options.scope, principal: new ServicePrincipal('apigateway.amazonaws.com'), sourceArn: Stack.of(route).formatArn({ diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts index 2f65902a6aaee..09be9668a1267 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts @@ -124,7 +124,7 @@ export class HttpRoute extends Resource implements IHttpRoute { route: this, scope: this, }); - integration = new HttpIntegration(this, `${this.node.id}-Integration`, { + integration = new HttpIntegration(this, `${this.construct.id}-Integration`, { httpApi: props.httpApi, integrationType: config.type, integrationUri: config.uri, diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts index a9e7de3ce9af2..9a171681b0715 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts @@ -103,7 +103,7 @@ export class HttpStage extends Resource implements IStage { apiMappingKey: props.domainMapping.mappingKey, }); // ensure the dependency - this.node.addDependency(props.domainMapping.domainName); + this.construct.addDependency(props.domainMapping.domainName); } } diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts index fac49b523e8ea..92f639a0c45ad 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts @@ -81,7 +81,7 @@ export class StepScalingAction extends cdk.Construct { // properties, or the ScalingTargetId property, but not both. // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationautoscaling-scalingpolicy.html const resource = new CfnScalingPolicy(this, 'Resource', { - policyName: props.policyName || this.node.uniqueId, + policyName: props.policyName || this.construct.uniqueId, policyType: 'StepScaling', scalingTargetId: props.scalingTarget.scalableTargetId, stepScalingPolicyConfiguration: { diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts index 8a314f0b1ac22..498de4e70b7ef 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts @@ -132,7 +132,7 @@ export class TargetTrackingScalingPolicy extends cdk.Construct { super(scope, id); const resource = new CfnScalingPolicy(this, 'Resource', { - policyName: props.policyName || this.node.uniqueId, + policyName: props.policyName || this.construct.uniqueId, policyType: 'TargetTrackingScaling', scalingTargetId: props.scalingTarget.scalableTargetId, targetTrackingScalingPolicyConfiguration: { diff --git a/packages/@aws-cdk/aws-appmesh/lib/mesh.ts b/packages/@aws-cdk/aws-appmesh/lib/mesh.ts index 8e39cb4657d1e..6479296b4ee33 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/mesh.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/mesh.ts @@ -170,7 +170,7 @@ export class Mesh extends MeshBase { constructor(scope: cdk.Construct, id: string, props: MeshProps = {}) { super(scope, id, { - physicalName: props.meshName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), + physicalName: props.meshName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), }); const mesh = new CfnMesh(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-appmesh/lib/route.ts b/packages/@aws-cdk/aws-appmesh/lib/route.ts index 8534ad70dcf14..01433c1d7f55f 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/route.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/route.ts @@ -145,7 +145,7 @@ export class Route extends cdk.Resource implements IRoute { constructor(scope: cdk.Construct, id: string, props: RouteProps) { super(scope, id, { - physicalName: props.routeName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), + physicalName: props.routeName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), }); this.virtualRouter = props.virtualRouter; diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts index f7a2548a48e7b..1b406878dc896 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts @@ -245,7 +245,7 @@ export class VirtualNode extends VirtualNodeBase { constructor(scope: cdk.Construct, id: string, props: VirtualNodeProps) { super(scope, id, { - physicalName: props.virtualNodeName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), + physicalName: props.virtualNodeName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), }); this.mesh = props.mesh; diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts index 3403b47378c5c..0249ace5e06f5 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts @@ -145,7 +145,7 @@ export class VirtualRouter extends VirtualRouterBase { constructor(scope: cdk.Construct, id: string, props: VirtualRouterProps) { super(scope, id, { - physicalName: props.virtualRouterName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), + physicalName: props.virtualRouterName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), }); this.mesh = props.mesh; diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts index 9cc678ec266a9..1ef3ef41eb788 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts @@ -106,7 +106,7 @@ export class VirtualService extends cdk.Resource implements IVirtualService { constructor(scope: cdk.Construct, id: string, props: VirtualServiceProps) { super(scope, id, { - physicalName: props.virtualServiceName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), + physicalName: props.virtualServiceName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), }); if (props.virtualNode && props.virtualRouter) { diff --git a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts index 07aa86ff45306..e19f7db7fd83a 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -471,7 +471,7 @@ abstract class AutoScalingGroupBase extends Resource implements IAutoScalingGrou ...props, }); - policy.node.addDependency(this.albTargetGroup.loadBalancerAttached); + policy.construct.addDependency(this.albTargetGroup.loadBalancerAttached); return policy; } @@ -595,7 +595,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements }); this.connections = new ec2.Connections({ securityGroups: [this.securityGroup] }); this.securityGroups.push(this.securityGroup); - this.node.applyAspect(new Tag(NAME_TAG, this.node.path)); + this.construct.applyAspect(new Tag(NAME_TAG, this.construct.path)); this.role = props.role || new iam.Role(this, 'InstanceRole', { roleName: PhysicalName.GENERATE_IF_NEEDED, @@ -632,7 +632,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements synthesizeBlockDeviceMappings(this, props.blockDevices) : undefined), }); - launchConfig.node.addDependency(this.role); + launchConfig.construct.addDependency(this.role); // desiredCapacity just reflects what the user has supplied. const desiredCapacity = props.desiredCapacity; @@ -659,7 +659,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements }); if (desiredCapacity !== undefined) { - this.node.addWarning('desiredCapacity has been configured. Be aware this will reset the size of your AutoScalingGroup on every deployment. See https://github.com/aws/aws-cdk/issues/5215'); + this.construct.addWarning('desiredCapacity has been configured. Be aware this will reset the size of your AutoScalingGroup on every deployment. See https://github.com/aws/aws-cdk/issues/5215'); } this.maxInstanceLifetime = props.maxInstanceLifetime; @@ -715,7 +715,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements resource: 'autoScalingGroup:*:autoScalingGroupName', resourceName: this.autoScalingGroupName, }); - this.node.defaultChild = this.autoScalingGroup; + this.construct.defaultChild = this.autoScalingGroup; this.applyUpdatePolicies(props); @@ -1259,7 +1259,7 @@ function synthesizeBlockDeviceMappings(construct: Construct, blockDevices: Block throw new Error('iops property is required with volumeType: EbsDeviceVolumeType.IO1'); } } else if (volumeType !== EbsDeviceVolumeType.IO1) { - construct.node.addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + construct.construct.addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); } } diff --git a/packages/@aws-cdk/aws-autoscaling/lib/lifecycle-hook.ts b/packages/@aws-cdk/aws-autoscaling/lib/lifecycle-hook.ts index 9c6f1d7f15322..841e5bc5b46c8 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/lifecycle-hook.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/lifecycle-hook.ts @@ -116,7 +116,7 @@ export class LifecycleHook extends Resource implements ILifecycleHook { // A LifecycleHook resource is going to do a permissions test upon creation, // so we have to make sure the role has full permissions before creating the // lifecycle hook. - resource.node.addDependency(this.role); + resource.construct.addDependency(this.role); this.lifecycleHookName = resource.ref; } diff --git a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts index 52242e44bda29..d992fd8ba602f 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts @@ -511,8 +511,8 @@ nodeunitShim({ pauseTime: cdk.Duration.seconds(345), }, }); - asg.node.applyAspect(new cdk.Tag('superfood', 'acai')); - asg.node.applyAspect(new cdk.Tag('notsuper', 'caramel', { applyToLaunchedInstances: false })); + asg.construct.applyAspect(new cdk.Tag('superfood', 'acai')); + asg.construct.applyAspect(new cdk.Tag('notsuper', 'caramel', { applyToLaunchedInstances: false })); // THEN expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { @@ -713,7 +713,7 @@ nodeunitShim({ }); // THEN - test.ok(asg.node.defaultChild instanceof autoscaling.CfnAutoScalingGroup); + test.ok(asg.construct.defaultChild instanceof autoscaling.CfnAutoScalingGroup); test.done(); }, @@ -958,8 +958,8 @@ nodeunitShim({ }); // THEN - test.deepEqual(asg.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(asg.node.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + test.deepEqual(asg.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(asg.construct.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); test.done(); }, @@ -985,8 +985,8 @@ nodeunitShim({ }); // THEN - test.deepEqual(asg.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(asg.node.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + test.deepEqual(asg.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(asg.construct.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); test.done(); }, diff --git a/packages/@aws-cdk/aws-backup/lib/plan.ts b/packages/@aws-cdk/aws-backup/lib/plan.ts index 99301fde7bde9..c9f9cc6d65c70 100644 --- a/packages/@aws-cdk/aws-backup/lib/plan.ts +++ b/packages/@aws-cdk/aws-backup/lib/plan.ts @@ -161,7 +161,7 @@ export class BackupPlan extends Resource implements IBackupPlan { deleteAfterDays: rule.props.deleteAfter?.toDays(), moveToColdStorageAfterDays: rule.props.moveToColdStorageAfter?.toDays(), }, - ruleName: rule.props.ruleName ?? `${this.node.id}Rule${this.rules.length}`, + ruleName: rule.props.ruleName ?? `${this.construct.id}Rule${this.rules.length}`, scheduleExpression: rule.props.scheduleExpression?.expressionString, startWindowMinutes: rule.props.startWindow?.toMinutes(), targetBackupVault: vault.backupVaultName, diff --git a/packages/@aws-cdk/aws-backup/lib/selection.ts b/packages/@aws-cdk/aws-backup/lib/selection.ts index 4e1ba54b472cb..9e6d6bd846565 100644 --- a/packages/@aws-cdk/aws-backup/lib/selection.ts +++ b/packages/@aws-cdk/aws-backup/lib/selection.ts @@ -94,7 +94,7 @@ export class BackupSelection extends Resource implements iam.IGrantable { backupPlanId: props.backupPlan.backupPlanId, backupSelection: { iamRoleArn: role.roleArn, - selectionName: props.backupSelectionName || this.node.id, + selectionName: props.backupSelectionName || this.construct.id, listOfTags: Lazy.anyValue({ produce: () => this.listOfTags, }, { omitEmptyArray: true }), @@ -126,7 +126,7 @@ export class BackupSelection extends Resource implements iam.IGrantable { } if (resource.construct) { - resource.construct.node.applyAspect(this.backupableResourcesCollector); + resource.construct.construct.applyAspect(this.backupableResourcesCollector); // Cannot push `this.backupableResourcesCollector.resources` to // `this.resources` here because it has not been evaluated yet. // Will be concatenated to `this.resources` in a `Lazy.listValue` diff --git a/packages/@aws-cdk/aws-backup/lib/vault.ts b/packages/@aws-cdk/aws-backup/lib/vault.ts index e9f85d8b160b1..dbbf01869871b 100644 --- a/packages/@aws-cdk/aws-backup/lib/vault.ts +++ b/packages/@aws-cdk/aws-backup/lib/vault.ts @@ -160,7 +160,7 @@ export class BackupVault extends Resource implements IBackupVault { private uniqueVaultName() { // Max length of 50 chars, get the last 50 chars - const id = this.node.uniqueId; + const id = this.construct.uniqueId; return id.substring(Math.max(id.length - 50, 0), id.length); } } diff --git a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts index 5d18ae0ca635e..3d9112d22a09d 100644 --- a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts +++ b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts @@ -386,7 +386,7 @@ export class ComputeEnvironment extends Resource implements IComputeEnvironment }); if (props.computeResources && props.computeResources.vpc) { - this.node.addDependency(props.computeResources.vpc); + this.construct.addDependency(props.computeResources.vpc); } this.computeEnvironmentArn = this.getResourceArnAttribute(computeEnvironment.ref, { diff --git a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts index 36258615fbf8e..bb25f2de40165 100644 --- a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts +++ b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts @@ -237,10 +237,10 @@ describe('Batch Compute Evironment', () => { ], Subnets: [ { - Ref: `${vpc.node.uniqueId}PrivateSubnet1Subnet865FB50A`, + Ref: `${vpc.construct.uniqueId}PrivateSubnet1Subnet865FB50A`, }, { - Ref: `${vpc.node.uniqueId}PrivateSubnet2Subnet23D3396F`, + Ref: `${vpc.construct.uniqueId}PrivateSubnet2Subnet23D3396F`, }, ], Tags: { diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/util.ts b/packages/@aws-cdk/aws-certificatemanager/lib/util.ts index 219bac1fd6a80..743b1e4faf8b7 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lib/util.ts +++ b/packages/@aws-cdk/aws-certificatemanager/lib/util.ts @@ -28,7 +28,7 @@ export function getCertificateRegion(cert: ICertificate): string | undefined { const { certificateArn, stack } = cert; if (isDnsValidatedCertificate(cert)) { - const requestResource = cert.node.findChild('CertificateRequestorResource').node.defaultChild; + const requestResource = cert.construct.findChild('CertificateRequestorResource').construct.defaultChild; // @ts-ignore const { _cfnProperties: properties } = requestResource; diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts b/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts index 0b39949203fe0..95cca4fa0efc2 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts @@ -335,7 +335,7 @@ export = { function matrixForResourceDependencyTest(testFunction: (test: Test, addDep: (source: CfnResource, target: CfnResource) => void) => void) { return { 'construct dependency'(test: Test) { - testFunction(test, (source, target) => source.node.addDependency(target)); + testFunction(test, (source, target) => source.construct.addDependency(target)); }, 'resource dependency'(test: Test) { testFunction(test, (source, target) => source.addDependsOn(target)); diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts index 4eedbf0e75c4c..94f42a6ecef7f 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts @@ -62,7 +62,7 @@ export = { const assembly = app.synth(); // THEN - const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, `${nested.node.uniqueId}.nested.template.json`), 'utf-8')); + const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, `${nested.construct.uniqueId}.nested.template.json`), 'utf-8')); test.deepEqual(template, { Resources: { ResourceInNestedStack: { @@ -847,7 +847,7 @@ export = { const resource = new CfnResource(nested, 'resource', { type: 'foo' }); // WHEN - resource.node.addMetadata('foo', 'bar'); + resource.construct.addMetadata('foo', 'bar'); // THEN: the first non-nested stack records the assembly metadata const asm = app.synth(); diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index 81cb0e7470ec4..2598c0cb10aa0 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -196,7 +196,7 @@ export class Distribution extends Resource implements IDistribution { } else { const originIndex = this.boundOrigins.length + 1; const scope = new Construct(this, `Origin${originIndex}`); - const originId = scope.node.uniqueId; + const originId = scope.construct.uniqueId; const originBindConfig = origin.bind(scope, { originId }); this.boundOrigins.push({ origin, originId, ...originBindConfig }); if (originBindConfig.failoverConfig) { @@ -223,7 +223,7 @@ export class Distribution extends Resource implements IDistribution { quantity: statusCodes.length, }, }, - id: new Construct(this, `OriginGroup${groupIndex}`).node.uniqueId, + id: new Construct(this, `OriginGroup${groupIndex}`).construct.uniqueId, members: { items: [ { originId }, diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index b2fc472adfd46..e93ddecaf1d79 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -924,7 +924,7 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu } const distribution = new CfnDistribution(this, 'CFDistribution', { distributionConfig }); - this.node.defaultChild = distribution; + this.construct.defaultChild = distribution; this.domainName = distribution.attrDomainName; this.distributionDomainName = distribution.attrDomainName; this.distributionId = distribution.ref; diff --git a/packages/@aws-cdk/aws-cloudfront/test/web_distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web_distribution.test.ts index c8b2fb322995f..5cf6751f50f87 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web_distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web_distribution.test.ts @@ -491,7 +491,7 @@ nodeunitShim({ ], }); - test.ok(distribution.node.defaultChild instanceof CfnDistribution); + test.ok(distribution.construct.defaultChild instanceof CfnDistribution); test.done(); }, diff --git a/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts b/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts index e41a50b1cb66d..217b578b8244b 100644 --- a/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts +++ b/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts @@ -295,14 +295,14 @@ export class Trail extends Resource { // Add a dependency on the bucket policy being updated, CloudTrail will test this upon creation. if (this.s3bucket.policy) { - trail.node.addDependency(this.s3bucket.policy); + trail.construct.addDependency(this.s3bucket.policy); } // If props.sendToCloudWatchLogs is set to true then the trail needs to depend on the created logsRole // so that it can create the log stream for the log group. This ensures the logsRole is created and propagated // before the trail tries to create the log stream. if (logsRole !== undefined) { - trail.node.addDependency(logsRole); + trail.construct.addDependency(logsRole); } } diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/composite-alarm.ts b/packages/@aws-cdk/aws-cloudwatch/lib/composite-alarm.ts index 4d20f5f3f1300..b204d776dfb1c 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/composite-alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/composite-alarm.ts @@ -119,7 +119,7 @@ export class CompositeAlarm extends AlarmBase { } private generateUniqueId(): string { - const name = this.node.uniqueId; + const name = this.construct.uniqueId; if (name.length > 240) { return name.substring(0, 120) + name.substring(name.length - 120); } diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index d4f349431b544..c5f231c443d8e 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -1007,7 +1007,7 @@ export class Project extends ProjectBase { } else { const securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, - description: 'Automatic generated security group for CodeBuild ' + this.node.uniqueId, + description: 'Automatic generated security group for CodeBuild ' + this.construct.uniqueId, allowAllOutbound: props.allowAllOutbound, }); securityGroups = [securityGroup]; @@ -1060,7 +1060,7 @@ export class Project extends ProjectBase { // add an explicit dependency between the EC2 Policy and this Project - // otherwise, creating the Project fails, as it requires these permissions // to be already attached to the Project's Role - project.node.addDependency(policy); + project.construct.addDependency(policy); } private validateCodePipelineSettings(artifacts: IArtifacts) { diff --git a/packages/@aws-cdk/aws-codecommit/lib/repository.ts b/packages/@aws-cdk/aws-codecommit/lib/repository.ts index 7dfb132138936..1c1d569d78ec8 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/repository.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/repository.ts @@ -367,7 +367,7 @@ export class Repository extends RepositoryBase { let name = options && options.name; if (!name) { - name = this.node.path + '/' + arn; + name = this.construct.path + '/' + arn; } if (this.triggers.find(prop => prop.name === name)) { diff --git a/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts index 074667136417f..154a644ce5a41 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts @@ -189,7 +189,7 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy this.addPostHook(props.postHook); } - (props.alias.node.defaultChild as lambda.CfnAlias).cfnOptions.updatePolicy = { + (props.alias.construct.defaultChild as lambda.CfnAlias).cfnOptions.updatePolicy = { codeDeployLambdaAliasUpdate: { applicationName: this.application.applicationName, deploymentGroupName: resource.ref, diff --git a/packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts b/packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts index f4d356e093204..30308c991b094 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts +++ b/packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts @@ -170,7 +170,7 @@ export class ProfilingGroup extends ProfilingGroupBase { } private generateUniqueId(): string { - const name = this.node.uniqueId; + const name = this.construct.uniqueId; if (name.length > 240) { return name.substring(0, 120) + name.substring(name.length - 120); } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts index 1982b0b8336bf..d59ece2b1d2e5 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts @@ -270,7 +270,7 @@ abstract class CloudFormationDeployAction extends CloudFormationAction { // pass role is not allowed for cross-account access - so, // create the deployment Role in the other account! this._deploymentRole = new iam.Role(roleStack, - `${stage.pipeline.node.uniqueId}-${stage.stageName}-${this.actionProperties.actionName}-DeploymentRole`, { + `${stage.pipeline.construct.uniqueId}-${stage.stageName}-${this.actionProperties.actionName}-DeploymentRole`, { assumedBy: new iam.ServicePrincipal('cloudformation.amazonaws.com'), roleName: cdk.PhysicalName.GENERATE_IF_NEEDED, }); @@ -500,7 +500,7 @@ class SingletonPolicy extends cdk.Construct implements iam.IGrantable { * @returns the SingletonPolicy for this role. */ public static forRole(role: iam.IRole): SingletonPolicy { - const found = role.node.tryFindChild(SingletonPolicy.UUID); + const found = role.construct.tryFindChild(SingletonPolicy.UUID); return (found as SingletonPolicy) || new SingletonPolicy(role); } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts index 2fa7a67b29b93..ea5735708e842 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts @@ -123,7 +123,7 @@ export class CodeCommitSourceAction extends Action { this.props.trigger === CodeCommitTrigger.EVENTS; if (createEvent) { const branchIdDisambiguator = this.branch === 'master' ? '' : `-${this.branch}-`; - this.props.repository.onCommit(`${stage.pipeline.node.uniqueId}${branchIdDisambiguator}EventRule`, { + this.props.repository.onCommit(`${stage.pipeline.construct.uniqueId}${branchIdDisambiguator}EventRule`, { target: new targets.CodePipeline(stage.pipeline), branches: [this.branch], }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts index b9261cf34d878..23f6158e8ef1b 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts @@ -89,7 +89,7 @@ export class EcrSourceAction extends Action { resources: [this.props.repository.repositoryArn], })); - this.props.repository.onCloudTrailImagePushed(stage.pipeline.node.uniqueId + 'SourceEventRule', { + this.props.repository.onCloudTrailImagePushed(stage.pipeline.construct.uniqueId + 'SourceEventRule', { target: new targets.CodePipeline(stage.pipeline), imageTag: this.props.imageTag, }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts index 7608aa3d94ae0..9891f79b7125e 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts @@ -110,8 +110,8 @@ export class S3SourceAction extends Action { protected bound(_scope: Construct, stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { if (this.props.trigger === S3Trigger.EVENTS) { - const id = stage.pipeline.node.uniqueId + 'SourceEventRule' + this.props.bucketKey; - if (this.props.bucket.node.tryFindChild(id)) { + const id = stage.pipeline.construct.uniqueId + 'SourceEventRule' + this.props.bucketKey; + if (this.props.bucket.construct.tryFindChild(id)) { // this means a duplicate path for the same bucket - error out throw new Error(`S3 source action with path '${this.props.bucketKey}' is already present in the pipeline for this source bucket`); } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts index 122add214cc3a..c6f8f9c6085fe 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts @@ -659,7 +659,7 @@ export = { }, })); - const otherStack = app.node.findChild('cross-account-support-stack-123456789012') as cdk.Stack; + const otherStack = app.construct.findChild('cross-account-support-stack-123456789012') as cdk.Stack; expect(otherStack).to(haveResourceLike('AWS::IAM::Role', { 'RoleName': 'pipelinestack-support-123loycfnactionrole56af64af3590f311bc50', })); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts index 6a7001630b3c5..0e284546218b7 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts @@ -653,8 +653,8 @@ export = { test.notEqual(usEast1Support, undefined); test.equal(usEast1Support.stack.region, 'us-east-1'); test.equal(usEast1Support.stack.account, pipelineAccount); - test.ok(usEast1Support.stack.node.id.indexOf('us-east-1') !== -1, - `expected '${usEast1Support.stack.node.id}' to contain 'us-east-1'`); + test.ok(usEast1Support.stack.construct.id.indexOf('us-east-1') !== -1, + `expected '${usEast1Support.stack.construct.id}' to contain 'us-east-1'`); test.done(); }, diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index b498c20945f83..960fe23e5496e 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -262,7 +262,7 @@ export class Pipeline extends PipelineBase { }); // this will produce a DependsOn for both the role and the policy resources. - codePipeline.node.addDependency(this.role); + codePipeline.construct.addDependency(this.role); this.artifactBucket.grantReadWrite(this.role); this.pipelineName = this.getResourceNameAttribute(codePipeline.ref); @@ -460,7 +460,7 @@ export class Pipeline extends PipelineBase { if (otherStack) { // check if the stack doesn't have this magic construct already const id = `CrossRegionReplicationSupport-d823f1d8-a990-4e5c-be18-4ac698532e65-${actionRegion}`; - let crossRegionSupportConstruct = otherStack.node.tryFindChild(id) as CrossRegionSupportConstruct; + let crossRegionSupportConstruct = otherStack.construct.tryFindChild(id) as CrossRegionSupportConstruct; if (!crossRegionSupportConstruct) { crossRegionSupportConstruct = new CrossRegionSupportConstruct(otherStack, id); } @@ -480,7 +480,7 @@ export class Pipeline extends PipelineBase { const app = this.requireApp(); const supportStackId = `cross-region-stack-${pipelineAccount}:${actionRegion}`; - let supportStack = app.node.tryFindChild(supportStackId) as CrossRegionSupportStack; + let supportStack = app.construct.tryFindChild(supportStackId) as CrossRegionSupportStack; if (!supportStack) { supportStack = new CrossRegionSupportStack(app, supportStackId, { pipelineStackName: pipelineStack.stackName, @@ -516,7 +516,7 @@ export class Pipeline extends PipelineBase { private generateNameForDefaultBucketKeyAlias(): string { const prefix = 'alias/codepipeline-'; const maxAliasLength = 256; - const uniqueId = this.node.uniqueId; + const uniqueId = this.construct.uniqueId; // take the last 256 - (prefix length) characters of uniqueId const startIndex = Math.max(0, uniqueId.length - (maxAliasLength - prefix.length)); return prefix + uniqueId.substring(startIndex).toLowerCase(); @@ -598,7 +598,7 @@ export class Pipeline extends PipelineBase { // generate a role in the other stack, that the Pipeline will assume for executing this action const ret = new iam.Role(otherAccountStack, - `${this.node.uniqueId}-${stage.stageName}-${action.actionProperties.actionName}-ActionRole`, { + `${this.construct.uniqueId}-${stage.stageName}-${action.actionProperties.actionName}-ActionRole`, { assumedBy: new iam.AccountPrincipal(pipelineStack.account), roleName: PhysicalName.GENERATE_IF_NEEDED, }); @@ -652,7 +652,7 @@ export class Pipeline extends PipelineBase { if (!targetAccountStack) { const stackId = `cross-account-support-stack-${targetAccount}`; const app = this.requireApp(); - targetAccountStack = app.node.tryFindChild(stackId) as Stack; + targetAccountStack = app.construct.tryFindChild(stackId) as Stack; if (!targetAccountStack) { targetAccountStack = new Stack(app, stackId, { stackName: `${pipelineStack.stackName}-support-${targetAccount}`, @@ -858,7 +858,7 @@ export class Pipeline extends PipelineBase { } private requireApp(): App { - const app = this.node.root; + const app = this.construct.root; if (!app || !App.isApp(app)) { throw new Error('Pipeline stack which uses cross-environment actions must be part of a CDK app'); } diff --git a/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts index 32f3604191e6a..5bc9a52fcef49 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts @@ -302,7 +302,7 @@ export = { const app = new cdk.App({ treeMetadata: false, // we can't set the context otherwise, because App will have a child }); - app.node.setContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT, true); + app.construct.setContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT, true); const pipelineStack = new cdk.Stack(app, 'PipelineStack', { env: { region: 'us-west-2', account: '123456789012' }, diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index 6ff23e96dde5d..9a09a6500bb04 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -842,7 +842,7 @@ export class UserPool extends UserPoolBase { externalId: props.smsRoleExternalId, }; } else { - const smsRoleExternalId = this.node.uniqueId.substr(0, 1223); // sts:ExternalId max length of 1224 + const smsRoleExternalId = this.construct.uniqueId.substr(0, 1223); // sts:ExternalId max length of 1224 const smsRole = props.smsRole ?? new Role(this, 'smsRole', { assumedBy: new ServicePrincipal('cognito-idp.amazonaws.com', { conditions: { diff --git a/packages/@aws-cdk/aws-config/lib/rule.ts b/packages/@aws-cdk/aws-config/lib/rule.ts index 12dd86b8ab1bd..2526f9ddd1981 100644 --- a/packages/@aws-cdk/aws-config/lib/rule.ts +++ b/packages/@aws-cdk/aws-config/lib/rule.ts @@ -357,7 +357,7 @@ export class CustomRule extends RuleNew { } // The lambda permission must be created before the rule - this.node.addDependency(props.lambdaFunction); + this.construct.addDependency(props.lambdaFunction); const rule = new CfnConfigRule(this, 'Resource', { configRuleName: this.physicalName, diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts index 339ef8f0b51a0..c8bb03243eab2 100644 --- a/packages/@aws-cdk/aws-docdb/lib/cluster.ts +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -303,7 +303,7 @@ export class DatabaseCluster extends DatabaseClusterBase { }); // HACK: Use an escape-hatch to apply a consistent removal policy to the // security group so we don't get errors when trying to delete the stack - (securityGroup.node.defaultChild as CfnResource).applyRemovalPolicy(props.removalPolicy, { + (securityGroup.construct.defaultChild as CfnResource).applyRemovalPolicy(props.removalPolicy, { applyToUpdateReplacePolicy: true, }); } @@ -389,7 +389,7 @@ export class DatabaseCluster extends DatabaseClusterBase { // We must have a dependency on the NAT gateway provider here to create // things in the right order. - instance.node.addDependency(internetConnectivityEstablished); + instance.construct.addDependency(internetConnectivityEstablished); this.instanceIdentifiers.push(instance.ref); this.instanceEndpoints.push(new Endpoint(instance.attrEndpoint, port)); @@ -413,7 +413,7 @@ export class DatabaseCluster extends DatabaseClusterBase { } const id = 'RotationSingleUser'; - const existing = this.node.tryFindChild(id); + const existing = this.construct.tryFindChild(id); if (existing) { throw new Error('A single user rotation was already added to this cluster.'); } diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index 957ea0bd40a85..581716d149ef9 100644 --- a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -775,6 +775,6 @@ describe('DatabaseCluster', () => { function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' }}); - stack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + stack.construct.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); return stack; } diff --git a/packages/@aws-cdk/aws-docdb/test/instance.test.ts b/packages/@aws-cdk/aws-docdb/test/instance.test.ts index 197e2e296fd8d..a4b3d849073f0 100644 --- a/packages/@aws-cdk/aws-docdb/test/instance.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/instance.test.ts @@ -173,7 +173,7 @@ class TestStack extends cdk.Stack { constructor(scope?: cdk.Construct, id?: string, props: cdk.StackProps = {}) { super(scope, id, props); - this.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + this.construct.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); this.vpc = new ec2.Vpc(this, 'VPC'); this.cluster = new DatabaseCluster(this, 'Database', { diff --git a/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts b/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts index d72ff1f42c176..03cad4f4ed397 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts @@ -40,7 +40,7 @@ export class GlobalTable extends cdk.Construct { constructor(scope: cdk.Construct, id: string, props: GlobalTableProps) { super(scope, id); - this.node.addWarning('The @aws-cdk/aws-dynamodb-global module has been deprecated in favor of @aws-cdk/aws-dynamodb.Table.replicationRegions'); + this.construct.addWarning('The @aws-cdk/aws-dynamodb-global module has been deprecated in favor of @aws-cdk/aws-dynamodb.Table.replicationRegions'); this._regionalTables = []; diff --git a/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts b/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts index e68f9230b69cd..077fdd73276b6 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts @@ -24,9 +24,9 @@ export = { 'global dynamo'(test: Test) { const stack = new Stack(); new GlobalTable(stack, CONSTRUCT_NAME, STACK_PROPS); - const topStack = stack.node.findChild(CONSTRUCT_NAME) as Stack; + const topStack = stack.construct.findChild(CONSTRUCT_NAME) as Stack; for ( const reg of STACK_PROPS.regions ) { - const tableStack = topStack.node.findChild(CONSTRUCT_NAME + '-' + reg) as Stack; + const tableStack = topStack.construct.findChild(CONSTRUCT_NAME + '-' + reg) as Stack; expect(tableStack).to(haveResource('AWS::DynamoDB::Table', { 'KeySchema': [ { @@ -46,7 +46,7 @@ export = { 'TableName': 'GlobalTable', })); } - const customResourceStack = stack.node.findChild(CONSTRUCT_NAME + '-CustomResource') as Stack; + const customResourceStack = stack.construct.findChild(CONSTRUCT_NAME + '-CustomResource') as Stack; expect(customResourceStack).to(haveResource('AWS::Lambda::Function', { Description: 'Lambda to make DynamoDB a global table', Handler: 'index.handler', diff --git a/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts b/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts index dbfd8761aff05..357306ee82ef0 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts @@ -11,7 +11,7 @@ export class ReplicaProvider extends NestedStack { public static getOrCreate(scope: Construct) { const stack = Stack.of(scope); const uid = '@aws-cdk/aws-dynamodb.ReplicaProvider'; - return stack.node.tryFindChild(uid) as ReplicaProvider || new ReplicaProvider(stack, uid); + return stack.construct.tryFindChild(uid) as ReplicaProvider || new ReplicaProvider(stack, uid); } /** diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index 2cb849d669f72..66aecf2e402c7 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -527,7 +527,7 @@ abstract class TableBase extends Resource implements ITable { */ public grantStream(grantee: iam.IGrantable, ...actions: string[]): iam.Grant { if (!this.tableStreamArn) { - throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`); + throw new Error(`DynamoDB Streams must be enabled on the table ${this.construct.path}`); } return iam.Grant.addToPrincipal({ @@ -558,7 +558,7 @@ abstract class TableBase extends Resource implements ITable { */ public grantTableListStreams(grantee: iam.IGrantable): iam.Grant { if (!this.tableStreamArn) { - throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`); + throw new Error(`DynamoDB Streams must be enabled on the table ${this.construct.path}`); } return iam.Grant.addToPrincipal({ @@ -729,7 +729,7 @@ abstract class TableBase extends Resource implements ITable { } if (opts.streamActions) { if (!this.tableStreamArn) { - throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`); + throw new Error(`DynamoDB Streams must be enabled on the table ${this.construct.path}`); } const resources = [ this.tableStreamArn]; const ret = iam.Grant.addToPrincipal({ @@ -920,7 +920,7 @@ export class Table extends TableBase { }); this.tableName = this.getResourceNameAttribute(this.table.ref); - if (props.tableName) { this.node.addMetadata('aws:cdk:hasPhysicalName', this.tableName); } + if (props.tableName) { this.construct.addMetadata('aws:cdk:hasPhysicalName', this.tableName); } this.tableStreamArn = streamSpecification ? this.table.attrStreamArn : undefined; @@ -1267,7 +1267,7 @@ export class Table extends TableBase { Region: region, }, }); - currentRegion.node.addDependency( + currentRegion.construct.addDependency( onEventHandlerPolicy.policy, isCompleteHandlerPolicy.policy, ); @@ -1279,7 +1279,7 @@ export class Table extends TableBase { const createReplica = new CfnCondition(this, `StackRegionNotEquals${region}`, { expression: Fn.conditionNot(Fn.conditionEquals(region, Aws.REGION)), }); - const cfnCustomResource = currentRegion.node.defaultChild as CfnCustomResource; + const cfnCustomResource = currentRegion.construct.defaultChild as CfnCustomResource; cfnCustomResource.cfnOptions.condition = createReplica; } @@ -1295,7 +1295,7 @@ export class Table extends TableBase { // have multiple table updates at the same time. The `isCompleteHandler` // of the provider waits until the replica is in an ACTIVE state. if (previousRegion) { - currentRegion.node.addDependency(previousRegion); + currentRegion.construct.addDependency(previousRegion); } previousRegion = currentRegion; } @@ -1349,7 +1349,7 @@ export class Table extends TableBase { switch (encryptionType) { case TableEncryption.CUSTOMER_MANAGED: const encryptionKey = props.encryptionKey ?? new kms.Key(this, 'Key', { - description: `Customer-managed key auto-created for encrypting DynamoDB table at ${this.node.path}`, + description: `Customer-managed key auto-created for encrypting DynamoDB table at ${this.construct.path}`, enableKeyRotation: true, }); @@ -1454,7 +1454,7 @@ class SourceTableAttachedPolicy extends Construct implements iam.IGrantable { public readonly policy: iam.IPolicy; public constructor(sourceTable: Table, role: iam.IRole) { - super(sourceTable, `SourceTableAttachedPolicy-${role.node.uniqueId}`); + super(sourceTable, `SourceTableAttachedPolicy-${role.construct.uniqueId}`); const policy = new iam.Policy(this, 'Resource', { roles: [role] }); this.policy = policy; diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 754a30150ace5..379613c699b92 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -324,7 +324,7 @@ test('when specifying every property', () => { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY, }); - table.node.applyAspect(new Tag('Environment', 'Production')); + table.construct.applyAspect(new Tag('Environment', 'Production')); expect(stack).toHaveResource('AWS::DynamoDB::Table', { @@ -357,7 +357,7 @@ test('when specifying sse with customer managed CMK', () => { encryption: TableEncryption.CUSTOMER_MANAGED, partitionKey: TABLE_PARTITION_KEY, }); - table.node.applyAspect(new Tag('Environment', 'Production')); + table.construct.applyAspect(new Tag('Environment', 'Production')); expect(stack).toHaveResource('AWS::DynamoDB::Table', { 'SSESpecification': { @@ -383,7 +383,7 @@ test('when specifying only encryptionKey', () => { encryptionKey, partitionKey: TABLE_PARTITION_KEY, }); - table.node.applyAspect(new Tag('Environment', 'Production')); + table.construct.applyAspect(new Tag('Environment', 'Production')); expect(stack).toHaveResource('AWS::DynamoDB::Table', { 'SSESpecification': { @@ -410,7 +410,7 @@ test('when specifying sse with customer managed CMK with encryptionKey provided encryptionKey, partitionKey: TABLE_PARTITION_KEY, }); - table.node.applyAspect(new Tag('Environment', 'Production')); + table.construct.applyAspect(new Tag('Environment', 'Production')); expect(stack).toHaveResource('AWS::DynamoDB::Table', { 'SSESpecification': { diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts index 3304c8defec2e..6c8d3f2899f80 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts @@ -58,7 +58,7 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL removalPolicy: RemovalPolicy.DESTROY, }); -tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); +tableWithGlobalAndLocalSecondaryIndex.construct.applyAspect(new Tag('Environment', 'Production')); tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ indexName: GSI_TEST_CASE_1, diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts index b1f3dca8b75a3..6b3777f439a4d 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts @@ -58,7 +58,7 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL removalPolicy: RemovalPolicy.DESTROY, }); -tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); +tableWithGlobalAndLocalSecondaryIndex.construct.applyAspect(new Tag('Environment', 'Production')); tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ indexName: GSI_TEST_CASE_1, partitionKey: GSI_PARTITION_KEY, diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts index 35c81b6486d3b..d2fe0f276d9fe 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts @@ -56,7 +56,7 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL removalPolicy: RemovalPolicy.DESTROY, }); -tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); +tableWithGlobalAndLocalSecondaryIndex.construct.applyAspect(new Tag('Environment', 'Production')); tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ indexName: GSI_TEST_CASE_1, partitionKey: GSI_PARTITION_KEY, diff --git a/packages/@aws-cdk/aws-ec2/lib/instance.ts b/packages/@aws-cdk/aws-ec2/lib/instance.ts index 79a6bb262d053..4e27914aa5ea2 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance.ts @@ -267,7 +267,7 @@ export class Instance extends Resource implements IInstance { } this.connections = new Connections({ securityGroups: [this.securityGroup] }); this.securityGroups.push(this.securityGroup); - Tag.add(this, NAME_TAG, props.instanceName || this.node.path); + Tag.add(this, NAME_TAG, props.instanceName || this.construct.path); this.role = props.role || new iam.Role(this, 'InstanceRole', { assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'), @@ -291,13 +291,13 @@ export class Instance extends Resource implements IInstance { if (selected.length === 1) { subnet = selected[0]; } else { - this.node.addError(`Need exactly 1 subnet to match AZ '${props.availabilityZone}', found ${selected.length}. Use a different availabilityZone.`); + this.construct.addError(`Need exactly 1 subnet to match AZ '${props.availabilityZone}', found ${selected.length}. Use a different availabilityZone.`); } } else { if (subnets.length > 0) { subnet = subnets[0]; } else { - this.node.addError(`Did not find any subnets matching '${JSON.stringify(props.vpcSubnets)}', please use a different selection.`); + this.construct.addError(`Did not find any subnets matching '${JSON.stringify(props.vpcSubnets)}', please use a different selection.`); } } if (!subnet) { @@ -322,10 +322,10 @@ export class Instance extends Resource implements IInstance { blockDeviceMappings: props.blockDevices !== undefined ? synthesizeBlockDeviceMappings(this, props.blockDevices) : undefined, privateIpAddress: props.privateIpAddress, }); - this.instance.node.addDependency(this.role); + this.instance.construct.addDependency(this.role); this.osType = imageConfig.osType; - this.node.defaultChild = this.instance; + this.construct.defaultChild = this.instance; this.instanceId = this.instance.ref; this.instanceAvailabilityZone = this.instance.attrAvailabilityZone; diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index e5dc208be10f0..712c7d3cb2aa3 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -70,7 +70,7 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { } public get uniqueId() { - return this.node.uniqueId; + return this.construct.uniqueId; } public addIngressRule(peer: IPeer, connection: Port, description?: string, remoteRule?: boolean) { @@ -81,7 +81,7 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { const [scope, id] = determineRuleScope(this, peer, connection, 'from', remoteRule); // Skip duplicates - if (scope.node.tryFindChild(id) === undefined) { + if (scope.construct.tryFindChild(id) === undefined) { new CfnSecurityGroupIngress(scope, id, { groupId: this.securityGroupId, ...peer.toIngressRuleConfig(), @@ -99,7 +99,7 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { const [scope, id] = determineRuleScope(this, peer, connection, 'to', remoteRule); // Skip duplicates - if (scope.node.tryFindChild(id) === undefined) { + if (scope.construct.tryFindChild(id) === undefined) { new CfnSecurityGroupEgress(scope, id, { groupId: this.securityGroupId, ...peer.toEgressRuleConfig(), @@ -363,7 +363,7 @@ export class SecurityGroup extends SecurityGroupBase { physicalName: props.securityGroupName, }); - const groupDescription = props.description || this.node.path; + const groupDescription = props.description || this.construct.path; this.allowAllOutbound = props.allowAllOutbound !== false; @@ -404,7 +404,7 @@ export class SecurityGroup extends SecurityGroupBase { // In the case of "allowAllOutbound", we don't add any more rules. There // is only one rule which allows all traffic and that subsumes any other // rule. - this.node.addWarning('Ignoring Egress rule since \'allowAllOutbound\' is set to true; To add customize rules, set allowAllOutbound=false on the SecurityGroup'); + this.construct.addWarning('Ignoring Egress rule since \'allowAllOutbound\' is set to true; To add customize rules, set allowAllOutbound=false on the SecurityGroup'); return; } else { // Otherwise, if the bogus rule exists we can now remove it because the diff --git a/packages/@aws-cdk/aws-ec2/lib/user-data.ts b/packages/@aws-cdk/aws-ec2/lib/user-data.ts index 617563e6cd05a..78ee18fb7c824 100644 --- a/packages/@aws-cdk/aws-ec2/lib/user-data.ts +++ b/packages/@aws-cdk/aws-ec2/lib/user-data.ts @@ -172,7 +172,7 @@ class LinuxUserData extends UserData { public addSignalOnExitCommand( resource: Resource ): void { const stack = Stack.of(resource); - const resourceID = stack.getLogicalId(resource.node.defaultChild as CfnElement); + const resourceID = stack.getLogicalId(resource.construct.defaultChild as CfnElement); this.addOnExitCommands(`/opt/aws/bin/cfn-signal --stack ${stack.stackName} --resource ${resourceID} --region ${stack.region} -e $exitCode || echo 'Failed to send Cloudformation Signal'`); } @@ -230,7 +230,7 @@ class WindowsUserData extends UserData { public addSignalOnExitCommand( resource: Resource ): void { const stack = Stack.of(resource); - const resourceID = stack.getLogicalId(resource.node.defaultChild as CfnElement); + const resourceID = stack.getLogicalId(resource.construct.defaultChild as CfnElement); this.addOnExitCommands(`cfn-signal --stack ${stack.stackName} --resource ${resourceID} --region ${stack.region} --success ($success.ToString().ToLower())`); } diff --git a/packages/@aws-cdk/aws-ec2/lib/util.ts b/packages/@aws-cdk/aws-ec2/lib/util.ts index 4f5a765b96bc5..91c0cd186960d 100644 --- a/packages/@aws-cdk/aws-ec2/lib/util.ts +++ b/packages/@aws-cdk/aws-ec2/lib/util.ts @@ -27,7 +27,7 @@ export function defaultSubnetName(type: SubnetType) { * All subnet names look like NAME <> "Subnet" <> INDEX */ export function subnetGroupNameFromConstructId(subnet: ISubnet) { - return subnet.node.id.replace(/Subnet\d+$/, ''); + return subnet.construct.id.replace(/Subnet\d+$/, ''); } /** diff --git a/packages/@aws-cdk/aws-ec2/lib/volume.ts b/packages/@aws-cdk/aws-ec2/lib/volume.ts index e33c32a9d63b6..ce62244e499c3 100644 --- a/packages/@aws-cdk/aws-ec2/lib/volume.ts +++ b/packages/@aws-cdk/aws-ec2/lib/volume.ts @@ -176,7 +176,7 @@ export function synthesizeBlockDeviceMappings(construct: Construct, blockDevices throw new Error('iops property is required with volumeType: EbsDeviceVolumeType.IO1'); } } else if (volumeType !== EbsDeviceVolumeType.IO1) { - construct.node.addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + construct.construct.addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); } } @@ -556,7 +556,7 @@ abstract class VolumeBase extends Resource implements IVolume { private calculateResourceTagValue(constructs: Construct[]): string { const md5 = crypto.createHash('md5'); - constructs.forEach(construct => md5.update(construct.node.uniqueId)); + constructs.forEach(construct => md5.update(construct.construct.uniqueId)); return md5.digest('hex'); } } diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index daaba4cd8a05f..ff53488411938 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -377,7 +377,7 @@ abstract class VpcBase extends Resource implements IVpc { const routeTableIds = allRouteTableIds(flatten(vpnRoutePropagation.map(s => this.selectSubnets(s).subnets))); if (routeTableIds.length === 0) { - this.node.addError(`enableVpnGateway: no subnets matching selection: '${JSON.stringify(vpnRoutePropagation)}'. Select other subnets to add routes to.`); + this.construct.addError(`enableVpnGateway: no subnets matching selection: '${JSON.stringify(vpnRoutePropagation)}'. Select other subnets to add routes to.`); } const routePropagation = new CfnVPNGatewayRoutePropagation(this, 'RoutePropagation', { @@ -387,7 +387,7 @@ abstract class VpcBase extends Resource implements IVpc { // The AWS::EC2::VPNGatewayRoutePropagation resource cannot use the VPN gateway // until it has successfully attached to the VPC. // See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpn-gatewayrouteprop.html - routePropagation.node.addDependency(attachment); + routePropagation.construct.addDependency(attachment); } /** @@ -1176,7 +1176,7 @@ export class Vpc extends VpcBase { this.vpcDefaultSecurityGroup = this.resource.attrDefaultSecurityGroup; this.vpcIpv6CidrBlocks = this.resource.attrIpv6CidrBlocks; - this.node.applyAspect(new Tag(NAME_TAG, this.node.path)); + this.construct.applyAspect(new Tag(NAME_TAG, this.construct.path)); this.availabilityZones = stack.availabilityZones; @@ -1363,8 +1363,8 @@ export class Vpc extends VpcBase { // These values will be used to recover the config upon provider import const includeResourceTypes = [CfnSubnet.CFN_RESOURCE_TYPE_NAME]; - subnet.node.applyAspect(new Tag(SUBNETNAME_TAG, subnetConfig.name, {includeResourceTypes})); - subnet.node.applyAspect(new Tag(SUBNETTYPE_TAG, subnetTypeTagValue(subnetConfig.subnetType), {includeResourceTypes})); + subnet.construct.applyAspect(new Tag(SUBNETNAME_TAG, subnetConfig.name, {includeResourceTypes})); + subnet.construct.applyAspect(new Tag(SUBNETTYPE_TAG, subnetTypeTagValue(subnetConfig.subnetType), {includeResourceTypes})); }); } } @@ -1482,7 +1482,7 @@ export class Subnet extends Resource implements ISubnet { Object.defineProperty(this, VPC_SUBNET_SYMBOL, { value: true }); - this.node.applyAspect(new Tag(NAME_TAG, this.node.path)); + this.construct.applyAspect(new Tag(NAME_TAG, this.construct.path)); this.availabilityZone = props.availabilityZone; const subnet = new CfnSubnet(this, 'Subnet', { @@ -1500,7 +1500,7 @@ export class Subnet extends Resource implements ISubnet { // was just created. However, the ACL can be replaced at a later time. this._networkAcl = NetworkAcl.fromNetworkAclId(this, 'Acl', subnet.attrNetworkAclAssociationId); this.subnetNetworkAclAssociationId = Lazy.stringValue({ produce: () => this._networkAcl.networkAclId }); - this.node.defaultChild = subnet; + this.construct.defaultChild = subnet; const table = new CfnRouteTable(this, 'RouteTable', { vpcId: props.vpcId, @@ -1529,7 +1529,7 @@ export class Subnet extends Resource implements ISubnet { destinationCidrBlock: '0.0.0.0/0', gatewayId, }); - route.node.addDependency(gatewayAttachment); + route.construct.addDependency(gatewayAttachment); // Since the 'route' depends on the gateway attachment, just // depending on the route is enough. @@ -1587,7 +1587,7 @@ export class Subnet extends Resource implements ISubnet { const scope = Construct.isConstruct(networkAcl) ? networkAcl : this; const other = Construct.isConstruct(networkAcl) ? this : networkAcl; - new SubnetNetworkAclAssociation(scope, id + other.node.uniqueId, { + new SubnetNetworkAclAssociation(scope, id + other.construct.uniqueId, { networkAcl, subnet: this, }); @@ -1891,10 +1891,10 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat if (!attrs.routeTableId) { const ref = Token.isUnresolved(attrs.subnetId) - ? `at '${scope.node.path}/${id}'` + ? `at '${scope.construct.path}/${id}'` : `'${attrs.subnetId}'`; // eslint-disable-next-line max-len - scope.node.addWarning(`No routeTableId was provided to the subnet ${ref}. Attempting to read its .routeTable.routeTableId will return null/undefined. (More info: https://github.com/aws/aws-cdk/pull/3171)`); + scope.construct.addWarning(`No routeTableId was provided to the subnet ${ref}. Attempting to read its .routeTable.routeTableId will return null/undefined. (More info: https://github.com/aws/aws-cdk/pull/3171)`); } this._availabilityZone = attrs.availabilityZone; @@ -1916,7 +1916,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public associateNetworkAcl(id: string, networkAcl: INetworkAcl): void { const scope = Construct.isConstruct(networkAcl) ? networkAcl : this; const other = Construct.isConstruct(networkAcl) ? this : networkAcl; - new SubnetNetworkAclAssociation(scope, id + other.node.uniqueId, { + new SubnetNetworkAclAssociation(scope, id + other.construct.uniqueId, { networkAcl, subnet: this, }); diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index 2a78f3cdf516e..ed451b1a774e7 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -237,8 +237,8 @@ nodeunitShim({ }); // THEN - test.deepEqual(instance.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(instance.node.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + test.deepEqual(instance.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(instance.construct.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); test.done(); }, @@ -264,8 +264,8 @@ nodeunitShim({ }); // THEN - test.deepEqual(instance.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(instance.node.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + test.deepEqual(instance.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(instance.construct.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); test.done(); }, diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts index a1c8e39c28141..5f2baf4eec680 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts @@ -393,13 +393,13 @@ nodeunitShim({ const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } }); // Setup context for stack AZs - stack.node.setContext( + stack.construct.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER, }).key, ['us-east-1a', 'us-east-1b', 'us-east-1c']); // Setup context for endpoint service AZs - stack.node.setContext( + stack.construct.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER, props: { @@ -438,7 +438,7 @@ nodeunitShim({ const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } }); // Setup context for stack AZs - stack.node.setContext( + stack.construct.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER, }).key, @@ -477,13 +477,13 @@ nodeunitShim({ const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } }); // Setup context for stack AZs - stack.node.setContext( + stack.construct.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER, }).key, ['us-east-1a', 'us-east-1b', 'us-east-1c']); // Setup context for endpoint service AZs - stack.node.setContext( + stack.construct.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER, props: { diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index 113a8eb7edd56..d2156a067e899 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -807,7 +807,7 @@ nodeunitShim({ const vpc = new Vpc(stack, 'VpcNetwork'); - test.ok(vpc.publicSubnets[0].node.defaultChild instanceof CfnSubnet); + test.ok(vpc.publicSubnets[0].construct.defaultChild instanceof CfnSubnet); test.done(); }, @@ -1033,8 +1033,8 @@ nodeunitShim({ const vpc = new Vpc(stack, 'TheVPC'); // overwrite to set propagate - vpc.node.applyAspect(new Tag('BusinessUnit', 'Marketing', {includeResourceTypes: [CfnVPC.CFN_RESOURCE_TYPE_NAME]})); - vpc.node.applyAspect(new Tag('VpcType', 'Good')); + vpc.construct.applyAspect(new Tag('BusinessUnit', 'Marketing', {includeResourceTypes: [CfnVPC.CFN_RESOURCE_TYPE_NAME]})); + vpc.construct.applyAspect(new Tag('VpcType', 'Good')); expect(stack).to(haveResource('AWS::EC2::VPC', hasTags(toCfnTags(allTags)))); const taggables = ['Subnet', 'InternetGateway', 'NatGateway', 'RouteTable']; const propTags = toCfnTags(tags); @@ -1049,12 +1049,12 @@ nodeunitShim({ const stack = getTestStack(); const vpc = new Vpc(stack, 'TheVPC'); for (const subnet of vpc.publicSubnets) { - const tag = {Key: 'Name', Value: subnet.node.path}; + const tag = {Key: 'Name', Value: subnet.construct.path}; expect(stack).to(haveResource('AWS::EC2::NatGateway', hasTags([tag]))); expect(stack).to(haveResource('AWS::EC2::RouteTable', hasTags([tag]))); } for (const subnet of vpc.privateSubnets) { - const tag = {Key: 'Name', Value: subnet.node.path}; + const tag = {Key: 'Name', Value: subnet.construct.path}; expect(stack).to(haveResource('AWS::EC2::RouteTable', hasTags([tag]))); } test.done(); @@ -1065,7 +1065,7 @@ nodeunitShim({ const vpc = new Vpc(stack, 'TheVPC'); const tag = {Key: 'Late', Value: 'Adder'}; expect(stack).notTo(haveResource('AWS::EC2::VPC', hasTags([tag]))); - vpc.node.applyAspect(new Tag(tag.Key, tag.Value)); + vpc.construct.applyAspect(new Tag(tag.Key, tag.Value)); expect(stack).to(haveResource('AWS::EC2::VPC', hasTags([tag]))); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts index 09c4a033a8476..07a297e9642b6 100644 --- a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts +++ b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts @@ -112,7 +112,7 @@ export class DockerImageAsset extends Construct implements assets.IAsset { }); if (props.repositoryName) { - this.node.addWarning('DockerImageAsset.repositoryName is deprecated. Override "core.Stack.addDockerImageAsset" to control asset locations'); + this.construct.addWarning('DockerImageAsset.repositoryName is deprecated. Override "core.Stack.addDockerImageAsset" to control asset locations'); } // include build context in "extra" so it will impact the hash diff --git a/packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts b/packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts index 54930ec176e14..d3affe4b26799 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts @@ -50,7 +50,7 @@ export = { }); // THEN - const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).buildArgs, { a: 'b' }); test.done(); }, @@ -69,7 +69,7 @@ export = { }); // THEN - const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).target, 'a-target'); test.done(); }, @@ -86,7 +86,7 @@ export = { }); // THEN - const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).file, 'Dockerfile.Custom'); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts index 3869d38d8826a..341307af9b88f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts @@ -380,9 +380,9 @@ export abstract class ApplicationLoadBalancedServiceBase extends cdk.Construct { */ protected getDefaultCluster(scope: cdk.Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; const stack = cdk.Stack.of(scope); - return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-multiple-target-groups-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-multiple-target-groups-service-base.ts index 5764b3fcdaeb5..f813f1431a966 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-multiple-target-groups-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-multiple-target-groups-service-base.ts @@ -385,9 +385,9 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru this.listeners.push(listener); } const domainName = this.createDomainName(lb, lbProps.domainName, lbProps.domainZone); - new CfnOutput(this, `LoadBalancerDNS${lb.node.id}`, { value: lb.loadBalancerDnsName }); + new CfnOutput(this, `LoadBalancerDNS${lb.construct.id}`, { value: lb.loadBalancerDnsName }); for (const protocol of protocolType) { - new CfnOutput(this, `ServiceURL${lb.node.id}${protocol.toLowerCase()}`, { value: protocol.toLowerCase() + '://' + domainName }); + new CfnOutput(this, `ServiceURL${lb.construct.id}${protocol.toLowerCase()}`, { value: protocol.toLowerCase() + '://' + domainName }); } } // set up default load balancer and listener. @@ -412,9 +412,9 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru */ protected getDefaultCluster(scope: Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs. - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; const stack = Stack.of(scope); - return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } protected createAWSLogDriver(prefix: string): AwsLogDriver { @@ -426,7 +426,7 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru return this.listener; } for (const listener of this.listeners) { - if (listener.node.id === name) { + if (listener.construct.id === name) { return listener; } } @@ -474,7 +474,7 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru const enableLogging = enableLoggingProp !== undefined ? enableLoggingProp : true; const logDriver = logDriverProp !== undefined ? logDriverProp : enableLogging - ? this.createAWSLogDriver(this.node.id) : undefined; + ? this.createAWSLogDriver(this.construct.id) : undefined; return logDriver; } @@ -558,7 +558,7 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name'); } - const record = new ARecord(this, `DNS${loadBalancer.node.id}`, { + const record = new ARecord(this, `DNS${loadBalancer.construct.id}`, { zone, recordName: name, target: RecordTarget.fromAlias(new LoadBalancerTarget(loadBalancer)), diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts index 567e952140b5b..070fb96a4f868 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts @@ -314,9 +314,9 @@ export abstract class NetworkLoadBalancedServiceBase extends cdk.Construct { */ protected getDefaultCluster(scope: cdk.Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; const stack = cdk.Stack.of(scope); - return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts index 54ec00ef64b1a..559451645a688 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts @@ -304,7 +304,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { this.listeners.push(listener); } this.createDomainName(lb, lbProps.domainName, lbProps.domainZone); - new CfnOutput(this, `LoadBalancerDNS${lb.node.id}`, { value: lb.loadBalancerDnsName }); + new CfnOutput(this, `LoadBalancerDNS${lb.construct.id}`, { value: lb.loadBalancerDnsName }); } // set up default load balancer and listener. this.loadBalancer = this.loadBalancers[0]; @@ -323,9 +323,9 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { */ protected getDefaultCluster(scope: Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs. - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; const stack = Stack.of(scope); - return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } protected createAWSLogDriver(prefix: string): AwsLogDriver { @@ -337,7 +337,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { return this.listener; } for (const listener of this.listeners) { - if (listener.node.id === name) { + if (listener.construct.id === name) { return listener; } } @@ -380,7 +380,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { const enableLogging = enableLoggingProp !== undefined ? enableLoggingProp : true; const logDriver = logDriverProp !== undefined ? logDriverProp : enableLogging - ? this.createAWSLogDriver(this.node.id) : undefined; + ? this.createAWSLogDriver(this.construct.id) : undefined; return logDriver; } @@ -427,7 +427,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name'); } - new ARecord(this, `DNS${loadBalancer.node.id}`, { + new ARecord(this, `DNS${loadBalancer.construct.id}`, { zone, recordName: name, target: RecordTarget.fromAlias(new LoadBalancerTarget(loadBalancer)), diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts index cd9e2f85f4633..f5a3f4c2b0e64 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts @@ -256,7 +256,7 @@ export abstract class QueueProcessingServiceBase extends Construct { this.logDriver = props.logDriver !== undefined ? props.logDriver : enableLogging - ? this.createAWSLogDriver(this.node.id) + ? this.createAWSLogDriver(this.construct.id) : undefined; // Add the queue name to environment variables @@ -304,9 +304,9 @@ export abstract class QueueProcessingServiceBase extends Construct { */ protected getDefaultCluster(scope: Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; const stack = Stack.of(scope); - return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts index 47f14de90e59a..5d972bfad47e6 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts @@ -161,9 +161,9 @@ export abstract class ScheduledTaskBase extends Construct { */ protected getDefaultCluster(scope: Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; const stack = Stack.of(scope); - return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts index f38cdbba5e3ca..46e37fd4fdd09 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts @@ -100,7 +100,7 @@ export class ApplicationLoadBalancedEc2Service extends ApplicationLoadBalancedSe const enableLogging = taskImageOptions.enableLogging !== undefined ? taskImageOptions.enableLogging : true; const logDriver = taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : enableLogging - ? this.createAWSLogDriver(this.node.id) : undefined; + ? this.createAWSLogDriver(this.construct.id) : undefined; const containerName = taskImageOptions.containerName !== undefined ? taskImageOptions.containerName : 'web'; const container = this.taskDefinition.addContainer(containerName, { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts index f6738f52ac687..8a1fb21af8995 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts @@ -98,7 +98,7 @@ export class NetworkLoadBalancedEc2Service extends NetworkLoadBalancedServiceBas const enableLogging = taskImageOptions.enableLogging !== undefined ? taskImageOptions.enableLogging : true; const logDriver = taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : enableLogging - ? this.createAWSLogDriver(this.node.id) : undefined; + ? this.createAWSLogDriver(this.construct.id) : undefined; const containerName = taskImageOptions.containerName !== undefined ? taskImageOptions.containerName : 'web'; const container = this.taskDefinition.addContainer(containerName, { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/scheduled-ecs-task.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/scheduled-ecs-task.ts index 7f0776dc812d4..ab4f89b5f851f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/scheduled-ecs-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/scheduled-ecs-task.ts @@ -107,7 +107,7 @@ export class ScheduledEc2Task extends ScheduledTaskBase { command: taskImageOptions.command, environment: taskImageOptions.environment, secrets: taskImageOptions.secrets, - logging: taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : this.createAWSLogDriver(this.node.id), + logging: taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : this.createAWSLogDriver(this.construct.id), }); } else { throw new Error('You must specify a taskDefinition or image'); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts index baa8a191410dc..b148eebbcd78f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts @@ -122,7 +122,7 @@ export class ApplicationLoadBalancedFargateService extends ApplicationLoadBalanc const enableLogging = taskImageOptions.enableLogging !== undefined ? taskImageOptions.enableLogging : true; const logDriver = taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : enableLogging - ? this.createAWSLogDriver(this.node.id) : undefined; + ? this.createAWSLogDriver(this.construct.id) : undefined; const containerName = taskImageOptions.containerName !== undefined ? taskImageOptions.containerName : 'web'; const container = this.taskDefinition.addContainer(containerName, { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts index c86e279ab2ea1..91fe54ce83734 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts @@ -118,7 +118,7 @@ export class NetworkLoadBalancedFargateService extends NetworkLoadBalancedServic const enableLogging = taskImageOptions.enableLogging !== undefined ? taskImageOptions.enableLogging : true; const logDriver = taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : enableLogging - ? this.createAWSLogDriver(this.node.id) : undefined; + ? this.createAWSLogDriver(this.construct.id) : undefined; const containerName = taskImageOptions.containerName !== undefined ? taskImageOptions.containerName : 'web'; const container = this.taskDefinition.addContainer(containerName, { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/scheduled-fargate-task.ts index e2c3dec274de8..d4a79b3315bf8 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/scheduled-fargate-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/scheduled-fargate-task.ts @@ -103,7 +103,7 @@ export class ScheduledFargateTask extends ScheduledTaskBase { command: taskImageOptions.command, environment: taskImageOptions.environment, secrets: taskImageOptions.secrets, - logging: taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : this.createAWSLogDriver(this.node.id), + logging: taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : this.createAWSLogDriver(this.construct.id), }); } else { throw new Error('You must specify one of: taskDefinition or image'); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts index 745bad2c660fc..152f41ff1e92f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts @@ -502,9 +502,9 @@ export = { }); // THEN - test.equal(ecsService.loadBalancer.node.id, 'lb1'); - test.equal(ecsService.listener.node.id, 'listener1'); - test.equal(ecsService.targetGroup.node.id, 'ECSTargetGroupweb80Group'); + test.equal(ecsService.loadBalancer.construct.id, 'lb1'); + test.equal(ecsService.listener.construct.id, 'listener1'); + test.equal(ecsService.targetGroup.construct.id, 'ECSTargetGroupweb80Group'); test.done(); }, @@ -1241,9 +1241,9 @@ export = { }); // THEN - test.equal(ecsService.loadBalancer.node.id, 'lb1'); - test.equal(ecsService.listener.node.id, 'listener1'); - test.equal(ecsService.targetGroup.node.id, 'ECSTargetGroupweb80Group'); + test.equal(ecsService.loadBalancer.construct.id, 'lb1'); + test.equal(ecsService.listener.construct.id, 'listener1'); + test.equal(ecsService.targetGroup.construct.id, 'ECSTargetGroupweb80Group'); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index acf23a40e9305..de24422c27159 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -356,7 +356,7 @@ export abstract class BaseService extends Resource }); if (props.deploymentController?.type === DeploymentControllerType.EXTERNAL) { - this.node.addWarning('taskDefinition and launchType are blanked out when using external deployment controller.'); + this.construct.addWarning('taskDefinition and launchType are blanked out when using external deployment controller.'); } this.serviceArn = this.getResourceArnAttribute(this.resource.ref, { @@ -675,7 +675,7 @@ export abstract class BaseService extends Resource // Service creation can only happen after the load balancer has // been associated with our target group(s), so add ordering dependency. - this.resource.node.addDependency(targetGroup.loadBalancerAttached); + this.resource.construct.addDependency(targetGroup.loadBalancerAttached); const targetType = this.taskDefinition.networkMode === NetworkMode.AWS_VPC ? elbv2.TargetType.IP : elbv2.TargetType.INSTANCE; return { targetType }; diff --git a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts index 94bc5bbef39b4..8be911a2a0cfd 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts @@ -266,7 +266,7 @@ export class TaskDefinition extends TaskDefinitionBase { constructor(scope: Construct, id: string, props: TaskDefinitionProps) { super(scope, id); - this.family = props.family || this.node.uniqueId; + this.family = props.family || this.construct.uniqueId; this.compatibility = props.compatibility; if (props.volumes) { diff --git a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts index 26da3b453bf46..cdcf56e8a494c 100644 --- a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts @@ -377,7 +377,7 @@ export class ContainerDefinition extends cdk.Construct { this.taskDefinition = props.taskDefinition; this.memoryLimitSpecified = props.memoryLimitMiB !== undefined || props.memoryReservationMiB !== undefined; this.linuxParameters = props.linuxParameters; - this.containerName = this.node.id; + this.containerName = this.construct.id; this.imageConfig = props.image.bind(this, this); if (props.logging) { @@ -389,7 +389,7 @@ export class ContainerDefinition extends cdk.Construct { this.secrets = []; for (const [name, secret] of Object.entries(props.secrets)) { if (this.taskDefinition.isFargateCompatible && secret.hasField) { - throw new Error(`Cannot specify secret JSON field for a task using the FARGATE launch type: '${name}' in container '${this.node.id}'`); + throw new Error(`Cannot specify secret JSON field for a task using the FARGATE launch type: '${name}' in container '${this.construct.id}'`); } secret.grantRead(this.taskDefinition.obtainExecutionRole()); this.secrets.push({ diff --git a/packages/@aws-cdk/aws-ecs/lib/images/repository.ts b/packages/@aws-cdk/aws-ecs/lib/images/repository.ts index 95d3675d63e11..b9419720d409c 100644 --- a/packages/@aws-cdk/aws-ecs/lib/images/repository.ts +++ b/packages/@aws-cdk/aws-ecs/lib/images/repository.ts @@ -37,7 +37,7 @@ export class RepositoryImage extends ContainerImage { public bind(scope: Construct, containerDefinition: ContainerDefinition): ContainerImageConfig { // name could be a Token - in that case, skip validation altogether if (!Token.isUnresolved(this.imageName) && ECR_IMAGE_REGEX.test(this.imageName)) { - scope.node.addWarning("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + scope.construct.addWarning("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); } if (this.props.credentials) { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts index 6b74bcf656e9a..fb2a10c6823ec 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts @@ -443,7 +443,7 @@ export = { }); // THEN - test.deepEqual(service.node.metadata[0].data, 'taskDefinition and launchType are blanked out when using external deployment controller.'); + test.deepEqual(service.construct.metadata[0].data, 'taskDefinition and launchType are blanked out when using external deployment controller.'); expect(stack).to(haveResource('AWS::ECS::Service', { Cluster: { Ref: 'EcsCluster97242B84', diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts index a22c4801fcebb..0559394e98e1a 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts @@ -519,7 +519,7 @@ export = { }); // THEN - test.deepEqual(container.node.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + test.deepEqual(container.construct.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); test.done(); }, @@ -538,7 +538,7 @@ export = { }); // THEN - test.deepEqual(container.node.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + test.deepEqual(container.construct.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts b/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts index 991901512a6d2..1ad1150804c67 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts @@ -321,7 +321,7 @@ export = { }); // THEN - test.deepEqual(service.node.metadata[0].data, 'taskDefinition and launchType are blanked out when using external deployment controller.'); + test.deepEqual(service.construct.metadata[0].data, 'taskDefinition and launchType are blanked out when using external deployment controller.'); expect(stack).to(haveResource('AWS::ECS::Service', { Cluster: { Ref: 'EcsCluster97242B84', diff --git a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts index 854503f388f7d..bf8b1aaff76e5 100644 --- a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts +++ b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts @@ -255,7 +255,7 @@ export class FileSystem extends Resource implements IFileSystem { filesystem.applyRemovalPolicy(props.removalPolicy); this.fileSystemId = filesystem.ref; - Tag.add(this, 'Name', props.fileSystemName || this.node.path); + Tag.add(this, 'Name', props.fileSystemName || this.construct.path); const securityGroup = (props.securityGroup || new ec2.SecurityGroup(this, 'EfsSecurityGroup', { vpc: props.vpc, diff --git a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts index 5104c069ec061..370c6bdff566e 100644 --- a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts +++ b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts @@ -210,7 +210,7 @@ test('auto-named if none provided', () => { // THEN expectCDK(stack).to(haveResource('AWS::EFS::FileSystem', { FileSystemTags: [ - {Key: 'Name', Value: fileSystem.node.path}, + {Key: 'Name', Value: fileSystem.construct.path}, ], })); }); diff --git a/packages/@aws-cdk/aws-eks-legacy/lib/cluster.ts b/packages/@aws-cdk/aws-eks-legacy/lib/cluster.ts index 0c5fcc2fb2e92..19fa809081a66 100644 --- a/packages/@aws-cdk/aws-eks-legacy/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks-legacy/lib/cluster.ts @@ -336,7 +336,7 @@ export class Cluster extends Resource implements ICluster { physicalName: props.clusterName, }); - this.node.addWarning('The @aws-cdk/aws-eks-legacy module will no longer be released as part of the AWS CDK starting March 1st, 2020. Please refer to https://github.com/aws/aws-cdk/issues/5544 for upgrade instructions'); + this.construct.addWarning('The @aws-cdk/aws-eks-legacy module will no longer be released as part of the AWS CDK starting March 1st, 2020. Please refer to https://github.com/aws/aws-cdk/issues/5544 for upgrade instructions'); const stack = Stack.of(this); @@ -636,11 +636,11 @@ export class Cluster extends Resource implements ICluster { // message (if token): "could not auto-tag public/private subnet with tag..." // message (if not token): "count not auto-tag public/private subnet xxxxx with tag..." const subnetID = Token.isUnresolved(subnet.subnetId) ? '' : ` ${subnet.subnetId}`; - this.node.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); + this.construct.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); continue; } - subnet.node.applyAspect(new Tag(tag, '1')); + subnet.construct.applyAspect(new Tag(tag, '1')); } }; diff --git a/packages/@aws-cdk/aws-eks-legacy/lib/helm-chart.ts b/packages/@aws-cdk/aws-eks-legacy/lib/helm-chart.ts index 714fc97e4da0d..03170db25fbca 100644 --- a/packages/@aws-cdk/aws-eks-legacy/lib/helm-chart.ts +++ b/packages/@aws-cdk/aws-eks-legacy/lib/helm-chart.ts @@ -84,7 +84,7 @@ export class HelmChart extends Construct { provider: CustomResourceProvider.lambda(handler), resourceType: HelmChart.RESOURCE_TYPE, properties: { - Release: props.release || this.node.uniqueId.slice(-63).toLowerCase(), // Helm has a 63 character limit for the name + Release: props.release || this.construct.uniqueId.slice(-63).toLowerCase(), // Helm has a 63 character limit for the name Chart: props.chart, Version: props.version, Values: (props.values ? stack.toJsonString(props.values) : undefined), @@ -99,7 +99,7 @@ export class HelmChart extends Construct { return undefined; } - let handler = cluster.node.tryFindChild('HelmChartHandler') as lambda.IFunction; + let handler = cluster.construct.tryFindChild('HelmChartHandler') as lambda.IFunction; if (!handler) { handler = new lambda.Function(cluster, 'HelmChartHandler', { code: lambda.Code.fromAsset(path.join(__dirname, 'helm-chart')), diff --git a/packages/@aws-cdk/aws-eks-legacy/lib/kubectl-layer.ts b/packages/@aws-cdk/aws-eks-legacy/lib/kubectl-layer.ts index 73168622e4ff4..79491964f295e 100644 --- a/packages/@aws-cdk/aws-eks-legacy/lib/kubectl-layer.ts +++ b/packages/@aws-cdk/aws-eks-legacy/lib/kubectl-layer.ts @@ -27,7 +27,7 @@ export class KubectlLayer extends Construct implements lambda.ILayerVersion { public static getOrCreate(scope: Construct, props: KubectlLayerProps = {}): KubectlLayer { const stack = Stack.of(scope); const id = 'kubectl-layer-' + (props.version ? props.version : '8C2542BC-BF2B-4DFE-B765-E181FD30A9A0'); - const exists = stack.node.tryFindChild(id) as KubectlLayer; + const exists = stack.construct.tryFindChild(id) as KubectlLayer; if (exists) { return exists; } @@ -48,7 +48,7 @@ export class KubectlLayer extends Construct implements lambda.ILayerVersion { constructor(scope: Construct, id: string, props: KubectlLayerProps = {}) { super(scope, id); - const uniqueId = crypto.createHash('md5').update(this.node.path).digest('hex'); + const uniqueId = crypto.createHash('md5').update(this.construct.path).digest('hex'); const version = props.version || KUBECTL_APP_VERSION; this.stack.templateOptions.transforms = [ 'AWS::Serverless-2016-10-31' ]; // required for AWS::Serverless diff --git a/packages/@aws-cdk/aws-eks-legacy/lib/user-data.ts b/packages/@aws-cdk/aws-eks-legacy/lib/user-data.ts index e889663520f32..89206b26a928d 100644 --- a/packages/@aws-cdk/aws-eks-legacy/lib/user-data.ts +++ b/packages/@aws-cdk/aws-eks-legacy/lib/user-data.ts @@ -7,7 +7,7 @@ export function renderUserData(clusterName: string, autoScalingGroup: autoscalin const stack = Stack.of(autoScalingGroup); // determine logical id of ASG so we can signal cloudformation - const cfn = autoScalingGroup.node.defaultChild as autoscaling.CfnAutoScalingGroup; + const cfn = autoScalingGroup.construct.defaultChild as autoscaling.CfnAutoScalingGroup; const asgLogicalId = cfn.logicalId; const extraArgs = new Array(); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts index f9c1a592586ca..3df44f8147841 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts @@ -19,7 +19,7 @@ export class ClusterResourceProvider extends NestedStack { public static getOrCreate(scope: Construct) { const stack = Stack.of(scope); const uid = '@aws-cdk/aws-eks.ClusterResourceProvider'; - return stack.node.tryFindChild(uid) as ClusterResourceProvider || new ClusterResourceProvider(stack, uid); + return stack.construct.tryFindChild(uid) as ClusterResourceProvider || new ClusterResourceProvider(stack, uid); } /** diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts index c885feaa476d2..c6f037c075140 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts @@ -162,7 +162,7 @@ export class ClusterResource extends Construct { }, }); - resource.node.addDependency(this.creationRole); + resource.construct.addDependency(this.creationRole); this.ref = resource.ref; this.attrEndpoint = Token.asString(resource.getAtt('Endpoint')); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index dbc34c53353af..65d24f12101be 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -637,7 +637,7 @@ export class Cluster extends Resource implements ICluster { // the security group and vpc must exist in order to properly delete the cluster (since we run `kubectl delete`). // this ensures that. - this._clusterResource.node.addDependency(this.kubctlProviderSecurityGroup, this.vpc); + this._clusterResource.construct.addDependency(this.kubctlProviderSecurityGroup, this.vpc); // see https://github.com/aws/aws-cdk/issues/9027 this._clusterResource.creationRole.addToPolicy(new iam.PolicyStatement({ @@ -659,7 +659,7 @@ export class Cluster extends Resource implements ICluster { }); // add the cluster resource itself as a dependency of the barrier - this._kubectlReadyBarrier.node.addDependency(this._clusterResource); + this._kubectlReadyBarrier.construct.addDependency(this._clusterResource); this.clusterName = this.getResourceNameAttribute(resource.ref); this.clusterArn = this.getResourceArnAttribute(resource.attrArn, clusterArnComponents(this.physicalName)); @@ -988,7 +988,7 @@ export class Cluster extends Resource implements ICluster { // add all profiles as a dependency of the "kubectl-ready" barrier because all kubectl- // resources can only be deployed after all fargate profiles are created. if (this._kubectlReadyBarrier) { - this._kubectlReadyBarrier.node.addDependency(fargateProfile); + this._kubectlReadyBarrier.construct.addDependency(fargateProfile); } return this._fargateProfiles; @@ -1009,7 +1009,7 @@ export class Cluster extends Resource implements ICluster { const uid = '@aws-cdk/aws-eks.KubectlProvider'; // singleton - let provider = this.stack.node.tryFindChild(uid) as KubectlProvider; + let provider = this.stack.construct.tryFindChild(uid) as KubectlProvider; if (!provider) { // create the provider. @@ -1046,7 +1046,7 @@ export class Cluster extends Resource implements ICluster { throw new Error('unexpected: kubectl enabled clusters should have a kubectl-ready barrier resource'); } - resourceScope.node.addDependency(this._kubectlReadyBarrier); + resourceScope.construct.addDependency(this._kubectlReadyBarrier); return provider; } @@ -1130,11 +1130,11 @@ export class Cluster extends Resource implements ICluster { // message (if token): "could not auto-tag public/private subnet with tag..." // message (if not token): "count not auto-tag public/private subnet xxxxx with tag..." const subnetID = Token.isUnresolved(subnet.subnetId) ? '' : ` ${subnet.subnetId}`; - this.node.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); + this.construct.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); continue; } - subnet.node.applyAspect(new Tag(tag, '1')); + subnet.construct.applyAspect(new Tag(tag, '1')); } }; diff --git a/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts b/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts index 428d96ae24b36..bef0ce6cf6bfc 100644 --- a/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts +++ b/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts @@ -189,7 +189,7 @@ export class FargateProfile extends Construct implements ITaggable { const clusterFargateProfiles = props.cluster._attachFargateProfile(this); if (clusterFargateProfiles.length > 1) { const previousProfile = clusterFargateProfiles[clusterFargateProfiles.length - 2]; - resource.node.addDependency(previousProfile); + resource.construct.addDependency(previousProfile); } // map the fargate pod execution role to the relevant groups in rbac diff --git a/packages/@aws-cdk/aws-eks/lib/helm-chart.ts b/packages/@aws-cdk/aws-eks/lib/helm-chart.ts index b46f0f8bbe09d..5207b94ea4ba8 100644 --- a/packages/@aws-cdk/aws-eks/lib/helm-chart.ts +++ b/packages/@aws-cdk/aws-eks/lib/helm-chart.ts @@ -107,7 +107,7 @@ export class HelmChart extends Construct { properties: { ClusterName: props.cluster.clusterName, RoleArn: props.cluster._kubectlCreationRole.roleArn, - Release: props.release ?? this.node.uniqueId.slice(-53).toLowerCase(), // Helm has a 53 character limit for the name + Release: props.release ?? this.construct.uniqueId.slice(-53).toLowerCase(), // Helm has a 53 character limit for the name Chart: props.chart, Version: props.version, Wait: wait || undefined, // props are stringified so we encode “false” as undefined diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-layer.ts b/packages/@aws-cdk/aws-eks/lib/kubectl-layer.ts index 84efa5325854a..fc2710c13b401 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-layer.ts +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-layer.ts @@ -29,7 +29,7 @@ export class KubectlLayer extends Construct implements lambda.ILayerVersion { public static getOrCreate(scope: Construct, props: KubectlLayerProps = {}): KubectlLayer { const stack = Stack.of(scope); const id = 'kubectl-layer-' + (props.version ? props.version : '8C2542BC-BF2B-4DFE-B765-E181FD30A9A0'); - const exists = stack.node.tryFindChild(id) as KubectlLayer; + const exists = stack.construct.tryFindChild(id) as KubectlLayer; if (exists) { return exists; } @@ -50,7 +50,7 @@ export class KubectlLayer extends Construct implements lambda.ILayerVersion { constructor(scope: Construct, id: string, props: KubectlLayerProps = {}) { super(scope, id); - const uniqueId = crypto.createHash('md5').update(this.node.path).digest('hex'); + const uniqueId = crypto.createHash('md5').update(this.construct.path).digest('hex'); const version = props.version || KUBECTL_APP_VERSION; this.stack.templateOptions.transforms = [ 'AWS::Serverless-2016-10-31' ]; // required for AWS::Serverless diff --git a/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts b/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts index 3e2ba0feb9abd..f9dca4ace1bb7 100644 --- a/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts @@ -361,11 +361,11 @@ export class LegacyCluster extends Resource implements ICluster { // message (if token): "could not auto-tag public/private subnet with tag..." // message (if not token): "count not auto-tag public/private subnet xxxxx with tag..." const subnetID = Token.isUnresolved(subnet.subnetId) ? '' : ` ${subnet.subnetId}`; - this.node.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); + this.construct.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); continue; } - subnet.node.applyAspect(new Tag(tag, '1')); + subnet.construct.applyAspect(new Tag(tag, '1')); } }; diff --git a/packages/@aws-cdk/aws-eks/lib/service-account.ts b/packages/@aws-cdk/aws-eks/lib/service-account.ts index 83da66fbfef73..665f6418b5278 100644 --- a/packages/@aws-cdk/aws-eks/lib/service-account.ts +++ b/packages/@aws-cdk/aws-eks/lib/service-account.ts @@ -57,7 +57,7 @@ export class ServiceAccount extends Construct implements IPrincipal { super(scope, id); const { cluster } = props; - this.serviceAccountName = props.name ?? this.node.uniqueId.toLowerCase(); + this.serviceAccountName = props.name ?? this.construct.uniqueId.toLowerCase(); this.serviceAccountNamespace = props.namespace ?? 'default'; /* Add conditions to the role to improve security. This prevents other pods in the same namespace to assume the role. diff --git a/packages/@aws-cdk/aws-eks/lib/user-data.ts b/packages/@aws-cdk/aws-eks/lib/user-data.ts index cf38cf7ee9761..5cad1fc2a57df 100644 --- a/packages/@aws-cdk/aws-eks/lib/user-data.ts +++ b/packages/@aws-cdk/aws-eks/lib/user-data.ts @@ -8,7 +8,7 @@ export function renderAmazonLinuxUserData(clusterName: string, autoScalingGroup: const stack = Stack.of(autoScalingGroup); // determine logical id of ASG so we can signal cloudformation - const cfn = autoScalingGroup.node.defaultChild as autoscaling.CfnAutoScalingGroup; + const cfn = autoScalingGroup.construct.defaultChild as autoscaling.CfnAutoScalingGroup; const asgLogicalId = cfn.logicalId; const extraArgs = new Array(); diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts index 6340be221a298..38b9ab11dc606 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts @@ -99,7 +99,7 @@ class EksClusterStack extends TestStack { }); // make sure namespace is deployed before the chart - nginxIngress.node.addDependency(nginxNamespace); + nginxIngress.construct.addDependency(nginxNamespace); // add a service account connected to a IAM role cluster.addServiceAccount('MyServiceAccount'); diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 576e4081e83c0..19d05afb89853 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -1386,7 +1386,7 @@ export = { }); // the kubectl provider is inside a nested stack. - const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; expect(nested).to(haveResource('AWS::Lambda::Function', { Environment: { Variables: { @@ -1427,7 +1427,7 @@ export = { region: 'us-east-1', }, }); - stack.node.setContext(`vpc-provider:account=${stack.account}:filter.vpc-id=${vpcId}:region=${stack.region}:returnAsymmetricSubnets=true`, { + stack.construct.setContext(`vpc-provider:account=${stack.account}:filter.vpc-id=${vpcId}:region=${stack.region}:returnAsymmetricSubnets=true`, { vpcId: vpcId, vpcCidrBlock: '10.0.0.0/16', subnetGroups: [ @@ -1467,7 +1467,7 @@ export = { endpointAccess: eks.EndpointAccess.PRIVATE, }); - const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; const template = expect(nested).value; test.deepEqual(template.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds, [ @@ -1488,7 +1488,7 @@ export = { })]}], }); - const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; const template = expect(nested).value; test.deepEqual(template.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds, [ @@ -1588,7 +1588,7 @@ export = { }); // the kubectl provider is inside a nested stack. - const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; expect(nested).to(haveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ @@ -1652,7 +1652,7 @@ export = { }); // the kubectl provider is inside a nested stack. - const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; test.equal(16, expect(nested).value.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds.length); test.done(); @@ -1701,7 +1701,7 @@ export = { }); // the kubectl provider is inside a nested stack. - const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; expect(nested).to(haveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts index d4c36abe15221..3e8096a61d297 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts @@ -248,7 +248,7 @@ export class LoadBalancer extends Resource implements IConnectable { crossZone: (props.crossZone === undefined || props.crossZone) ? true : false, }); if (props.internetFacing) { - this.elb.node.addDependency(selectedSubnets.internetConnectivityEstablished); + this.elb.construct.addDependency(selectedSubnets.internetConnectivityEstablished); } ifUndefined(props.listeners, []).forEach(b => this.addListener(b)); diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/test.loadbalancer.ts b/packages/@aws-cdk/aws-elasticloadbalancing/test/test.loadbalancer.ts index fdbfca95ae4eb..550a21f520ec2 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/test.loadbalancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/test.loadbalancer.ts @@ -7,7 +7,7 @@ import { ILoadBalancerTarget, LoadBalancer, LoadBalancingProtocol } from '../lib export = { 'test specifying nonstandard port works'(test: Test) { const stack = new Stack(undefined, undefined, { env: { account: '1234', region: 'test' }}); - stack.node.setContext('availability-zones:1234:test', ['test-1a', 'test-1b']); + stack.construct.setContext('availability-zones:1234:test', ['test-1a', 'test-1b']); const vpc = new Vpc(stack, 'VCP'); const lb = new LoadBalancer(stack, 'LB', { vpc }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.ts index f9ab2c015b382..aa4172256a44e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.ts @@ -44,7 +44,7 @@ class CognitoStack extends Stack { ], }, }); - const cfnClient = userPoolClient.node.defaultChild as cognito.CfnUserPoolClient; + const cfnClient = userPoolClient.construct.defaultChild as cognito.CfnUserPoolClient; cfnClient.addPropertyOverride('RefreshTokenValidity', 1); cfnClient.addPropertyOverride('SupportedIdentityProviders', ['COGNITO']); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts index a8de884e9f2c0..3234c5b249532 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts @@ -298,7 +298,7 @@ export class ApplicationListenerRule extends cdk.Construct { // Instead, signal this through a warning. // @deprecate: upon the next major version bump, replace this with a `throw` if (this.action) { - this.node.addWarning('An Action already existed on this ListenerRule and was replaced. Configure exactly one default Action.'); + this.construct.addWarning('An Action already existed on this ListenerRule and was replaced. Configure exactly one default Action.'); } action.bind(this, this.listener, this); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts index a9e469394b8c3..be195010d03bf 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts @@ -69,7 +69,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic this.ipAddressType = props.ipAddressType ?? IpAddressType.IPV4; this.securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, - description: `Automatically created Security Group for ELB ${this.node.uniqueId}`, + description: `Automatically created Security Group for ELB ${this.construct.uniqueId}`, allowAllOutbound: false, }); this.connections = new ec2.Connections({ securityGroups: [this.securityGroup] }); @@ -562,12 +562,12 @@ class ImportedApplicationLoadBalancer extends Resource implements IApplicationLo public get loadBalancerCanonicalHostedZoneId(): string { if (this.props.loadBalancerCanonicalHostedZoneId) { return this.props.loadBalancerCanonicalHostedZoneId; } // eslint-disable-next-line max-len - throw new Error(`'loadBalancerCanonicalHostedZoneId' was not provided when constructing Application Load Balancer ${this.node.path} from attributes`); + throw new Error(`'loadBalancerCanonicalHostedZoneId' was not provided when constructing Application Load Balancer ${this.construct.path} from attributes`); } public get loadBalancerDnsName(): string { if (this.props.loadBalancerDnsName) { return this.props.loadBalancerDnsName; } // eslint-disable-next-line max-len - throw new Error(`'loadBalancerDnsName' was not provided when constructing Application Load Balancer ${this.node.path} from attributes`); + throw new Error(`'loadBalancerDnsName' was not provided when constructing Application Load Balancer ${this.construct.path} from attributes`); } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 9d6561356f5e9..66e251538ff39 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -374,11 +374,11 @@ export interface IApplicationTargetGroup extends ITargetGroup { class ImportedApplicationTargetGroup extends ImportedTargetGroupBase implements IApplicationTargetGroup { public registerListener(_listener: IApplicationListener, _associatingConstruct?: IConstruct) { // Nothing to do, we know nothing of our members - this.node.addWarning('Cannot register listener on imported target group -- security groups might need to be updated manually'); + this.construct.addWarning('Cannot register listener on imported target group -- security groups might need to be updated manually'); } public registerConnectable(_connectable: ec2.IConnectable, _portRange?: ec2.Port | undefined): void { - this.node.addWarning('Cannot register connectable on imported target group -- security groups might need to be updated manually'); + this.construct.addWarning('Cannot register connectable on imported target group -- security groups might need to be updated manually'); } public addTarget(...targets: IApplicationLoadBalancerTarget[]) { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts index 28e23cc56a257..4c197a6b71347 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts @@ -70,13 +70,13 @@ export class NetworkLoadBalancer extends BaseLoadBalancer implements INetworkLoa public get loadBalancerCanonicalHostedZoneId(): string { if (attrs.loadBalancerCanonicalHostedZoneId) { return attrs.loadBalancerCanonicalHostedZoneId; } // eslint-disable-next-line max-len - throw new Error(`'loadBalancerCanonicalHostedZoneId' was not provided when constructing Network Load Balancer ${this.node.path} from attributes`); + throw new Error(`'loadBalancerCanonicalHostedZoneId' was not provided when constructing Network Load Balancer ${this.construct.path} from attributes`); } public get loadBalancerDnsName(): string { if (attrs.loadBalancerDnsName) { return attrs.loadBalancerDnsName; } // eslint-disable-next-line max-len - throw new Error(`'loadBalancerDnsName' was not provided when constructing Network Load Balancer ${this.node.path} from attributes`); + throw new Error(`'loadBalancerDnsName' was not provided when constructing Network Load Balancer ${this.construct.path} from attributes`); } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts index d9405bff1f729..767af7db4eb66 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts @@ -50,7 +50,7 @@ export abstract class BaseListener extends Resource { // Instead, signal this through a warning. // @deprecate: upon the next major version bump, replace this with a `throw` if (this.defaultAction) { - this.node.addWarning('A default Action already existed on this Listener and was replaced. Configure exactly one default Action.'); + this.construct.addWarning('A default Action already existed on this Listener and was replaced. Configure exactly one default Action.'); } this.defaultAction = action; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts index 7c7447d19eba0..6e6693b3081db 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts @@ -142,7 +142,7 @@ export abstract class BaseLoadBalancer extends Resource { ...additionalProps, }); if (internetFacing) { - resource.node.addDependency(internetConnectivityEstablished); + resource.construct.addDependency(internetConnectivityEstablished); } if (baseProps.deletionProtection) { this.setAttribute('deletion_protection.enabled', 'true'); } @@ -180,7 +180,7 @@ export abstract class BaseLoadBalancer extends Resource { bucket.grantPut(new iam.AccountPrincipal(account), `${(prefix ? prefix + '/' : '')}AWSLogs/${Stack.of(this).account}/*`); // make sure the bucket's policy is created before the ALB (see https://github.com/aws/aws-cdk/issues/1633) - this.node.addDependency(bucket); + this.construct.addDependency(bucket); } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index f35642e6d4c9e..affdbc2b8f5bd 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -313,7 +313,7 @@ export abstract class TargetGroupBase extends cdk.Construct implements ITargetGr const ret = super.validate(); if (this.targetType === undefined && this.targetsJson.length === 0) { - this.node.addWarning("When creating an empty TargetGroup, you should specify a 'targetType' (this warning may become an error in the future)."); + this.construct.addWarning("When creating an empty TargetGroup, you should specify a 'targetType' (this warning may become an error in the future)."); } if (this.targetType !== TargetType.LAMBDA && this.vpc === undefined) { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts index 188fd80ea4eea..86cec342bd85f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts @@ -1359,6 +1359,6 @@ export = { class ResourceWithLBDependency extends cdk.CfnResource { constructor(scope: cdk.Construct, id: string, targetGroup: elbv2.ITargetGroup) { super(scope, id, { type: 'Test::Resource' }); - this.node.addDependency(targetGroup.loadBalancerAttached); + this.construct.addDependency(targetGroup.loadBalancerAttached); } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts index 5ce09e6f82ef3..53778415690d5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts @@ -38,7 +38,7 @@ const ipv6Block = new ec2.CfnVPCCidrBlock( // Get the vpc's internet gateway so we can create default routes for the // public subnets. const internetGateway = valueOrDie( - vpc.node.children.find(c => c instanceof ec2.CfnInternetGateway), + vpc.construct.children.find(c => c instanceof ec2.CfnInternetGateway), new Error('Couldnt find an internet gateway'), ); @@ -54,7 +54,7 @@ vpc.publicSubnets.forEach((subnet, idx) => { // Find a CfnSubnet (raw cloudformation resources) child to the public // subnet nodes. const cfnSubnet = valueOrDie( - subnet.node.children.find(c => c instanceof ec2.CfnSubnet), + subnet.construct.children.find(c => c instanceof ec2.CfnSubnet), new Error('Couldnt find a CfnSubnet'), ); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.ts index 2b6ad8cff5c90..b3fac7df3efae 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.ts @@ -24,7 +24,7 @@ const group = listener.addTargets('Target', { targets: [new elbv2.IpTarget('10.0.1.1')], }); -group.node.addDependency(vpc.internetConnectivityEstablished); +group.construct.addDependency(vpc.internetConnectivityEstablished); // The target's security group must allow being routed by the LB and the clients. diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/test.listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/test.listener.ts index a94421e357154..16eba5fb4766e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/test.listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/test.listener.ts @@ -339,6 +339,6 @@ export = { class ResourceWithLBDependency extends cdk.CfnResource { constructor(scope: cdk.Construct, id: string, targetGroup: elbv2.ITargetGroup) { super(scope, id, { type: 'Test::Resource' }); - this.node.addDependency(targetGroup.loadBalancerAttached); + this.construct.addDependency(targetGroup.loadBalancerAttached); } } diff --git a/packages/@aws-cdk/aws-events-targets/lib/aws-api.ts b/packages/@aws-cdk/aws-events-targets/lib/aws-api.ts index 9eade462aae13..b40ae306d106a 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/aws-api.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/aws-api.ts @@ -81,7 +81,7 @@ export class AwsApi implements events.IRuleTarget { * result from an EventBridge event. */ public bind(rule: events.IRule, id?: string): events.RuleTargetConfig { - const handler = new lambda.SingletonFunction(rule as events.Rule, `${rule.node.id}${id}Handler`, { + const handler = new lambda.SingletonFunction(rule as events.Rule, `${rule.construct.id}${id}Handler`, { code: lambda.Code.fromAsset(path.join(__dirname, 'aws-api-handler')), runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', diff --git a/packages/@aws-cdk/aws-events-targets/lib/batch.ts b/packages/@aws-cdk/aws-events-targets/lib/batch.ts index 69f9a52fdbb35..2e45b693137fd 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/batch.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/batch.ts @@ -59,7 +59,7 @@ export class BatchJob implements events.IRuleTarget { public bind(rule: events.IRule, _id?: string): events.RuleTargetConfig { const batchParameters: events.CfnRule.BatchParametersProperty = { jobDefinition: this.jobDefinition.jobDefinitionArn, - jobName: this.props.jobName ?? rule.node.uniqueId, + jobName: this.props.jobName ?? rule.construct.uniqueId, arrayProperties: this.props.size ? { size: this.props.size } : undefined, retryStrategy: this.props.attempts ? { attempts: this.props.attempts } : undefined, }; diff --git a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts index 77fdae5d37208..7c48c4ce8216d 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts @@ -115,7 +115,7 @@ export class EcsTask implements events.IRuleTarget { // Security groups are only configurable with the "awsvpc" network mode. if (this.taskDefinition.networkMode !== ecs.NetworkMode.AWS_VPC) { if (props.securityGroup !== undefined || props.securityGroups !== undefined) { - this.taskDefinition.node.addWarning('security groups are ignored when network mode is not awsvpc'); + this.taskDefinition.construct.addWarning('security groups are ignored when network mode is not awsvpc'); } return; } @@ -123,7 +123,7 @@ export class EcsTask implements events.IRuleTarget { this.securityGroups = props.securityGroups; return; } - let securityGroup = props.securityGroup || this.taskDefinition.node.tryFindChild('SecurityGroup') as ec2.ISecurityGroup; + let securityGroup = props.securityGroup || this.taskDefinition.construct.tryFindChild('SecurityGroup') as ec2.ISecurityGroup; securityGroup = securityGroup || new ec2.SecurityGroup(this.taskDefinition, 'SecurityGroup', { vpc: this.props.cluster.vpc }); this.securityGroup = securityGroup; // Maintain backwards-compatibility for customers that read the generated security group. this.securityGroups = [securityGroup]; diff --git a/packages/@aws-cdk/aws-events-targets/lib/util.ts b/packages/@aws-cdk/aws-events-targets/lib/util.ts index ddcd83adb5f1b..a116aab8849cd 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/util.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/util.ts @@ -11,7 +11,7 @@ import { Construct, IConstruct } from '@aws-cdk/core'; */ export function singletonEventRole(scope: IConstruct, policyStatements: iam.PolicyStatement[]): iam.IRole { const id = 'EventsRole'; - const existing = scope.node.tryFindChild(id) as iam.IRole; + const existing = scope.construct.tryFindChild(id) as iam.IRole; if (existing) { return existing; } const role = new iam.Role(scope as Construct, id, { @@ -27,7 +27,7 @@ export function singletonEventRole(scope: IConstruct, policyStatements: iam.Poli * Allows a Lambda function to be called from a rule */ export function addLambdaPermission(rule: events.IRule, handler: lambda.IFunction): void { - const permissionId = `AllowEventRule${rule.node.uniqueId}`; + const permissionId = `AllowEventRule${rule.construct.uniqueId}`; if (!handler.permissionsNode.tryFindChild(permissionId)) { handler.addPermission(permissionId, { action: 'lambda:InvokeFunction', diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts b/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts index 3e2b5e524ba3b..7a3ff8a30e1a7 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts @@ -95,7 +95,7 @@ describe('CodePipeline event target', () => { const role = new iam.Role(stack, 'MyExampleRole', { assumedBy: new iam.AnyPrincipal(), }); - const roleResource = role.node.defaultChild as CfnElement; + const roleResource = role.construct.defaultChild as CfnElement; roleResource.overrideLogicalId('MyRole'); // to make it deterministic in the assertion below rule.addTarget(new targets.CodePipeline(pipeline, { diff --git a/packages/@aws-cdk/aws-events/lib/event-bus.ts b/packages/@aws-cdk/aws-events/lib/event-bus.ts index 366c259685527..1697cec293e1a 100644 --- a/packages/@aws-cdk/aws-events/lib/event-bus.ts +++ b/packages/@aws-cdk/aws-events/lib/event-bus.ts @@ -218,7 +218,7 @@ export class EventBus extends Resource implements IEventBus { constructor(scope: Construct, id: string, props?: EventBusProps) { const { eventBusName, eventSourceName } = EventBus.eventBusProps( - Lazy.stringValue({ produce: () => this.node.uniqueId }), + Lazy.stringValue({ produce: () => this.construct.uniqueId }), props, ); diff --git a/packages/@aws-cdk/aws-events/lib/rule.ts b/packages/@aws-cdk/aws-events/lib/rule.ts index 1b19b5f1174a9..a7d630087ce48 100644 --- a/packages/@aws-cdk/aws-events/lib/rule.ts +++ b/packages/@aws-cdk/aws-events/lib/rule.ts @@ -221,11 +221,11 @@ export class Rule extends Resource implements IRule { // (EventBridge verifies whether you have permissions to the targets on rule creation), // but it's common for the target stack to depend on the source stack // (that's the case with CodePipeline, for example) - const sourceApp = this.node.root; + const sourceApp = this.construct.root; if (!sourceApp || !App.isApp(sourceApp)) { throw new Error('Event stack which uses cross-account targets must be part of a CDK app'); } - const targetApp = targetProps.targetResource.node.root; + const targetApp = targetProps.targetResource.construct.root; if (!targetApp || !App.isApp(targetApp)) { throw new Error('Target stack which uses cross-account event targets must be part of a CDK app'); } @@ -233,7 +233,7 @@ export class Rule extends Resource implements IRule { throw new Error('Event stack and target stack must belong to the same CDK app'); } const stackId = `EventBusPolicy-${sourceAccount}-${targetRegion}-${targetAccount}`; - let eventBusPolicyStack: Stack = sourceApp.node.tryFindChild(stackId) as Stack; + let eventBusPolicyStack: Stack = sourceApp.construct.tryFindChild(stackId) as Stack; if (!eventBusPolicyStack) { eventBusPolicyStack = new Stack(sourceApp, stackId, { env: { @@ -275,7 +275,7 @@ export class Rule extends Resource implements IRule { } } - new CopyRule(targetStack, `${this.node.uniqueId}-${id}`, { + new CopyRule(targetStack, `${this.construct.uniqueId}-${id}`, { targets: [target], eventPattern: this.eventPattern, schedule: this.scheduleExpression ? Schedule.expression(this.scheduleExpression) : undefined, diff --git a/packages/@aws-cdk/aws-events/test/test.rule.ts b/packages/@aws-cdk/aws-events/test/test.rule.ts index e6ae493b60ab7..a6c9cc106e475 100644 --- a/packages/@aws-cdk/aws-events/test/test.rule.ts +++ b/packages/@aws-cdk/aws-events/test/test.rule.ts @@ -361,7 +361,7 @@ export = { const t1: IRuleTarget = { bind: (eventRule: IRule) => { receivedRuleArn = eventRule.ruleArn; - receivedRuleId = eventRule.node.uniqueId; + receivedRuleId = eventRule.construct.uniqueId; return { id: '', @@ -375,7 +375,7 @@ export = { rule.addTarget(t1); test.deepEqual(stack.resolve(receivedRuleArn), stack.resolve(rule.ruleArn)); - test.deepEqual(receivedRuleId, rule.node.uniqueId); + test.deepEqual(receivedRuleId, rule.construct.uniqueId); test.done(); }, @@ -678,7 +678,7 @@ export = { ], })); - const eventBusPolicyStack = app.node.findChild(`EventBusPolicy-${sourceAccount}-us-west-2-${targetAccount}`) as cdk.Stack; + const eventBusPolicyStack = app.construct.findChild(`EventBusPolicy-${sourceAccount}-us-west-2-${targetAccount}`) as cdk.Stack; expect(eventBusPolicyStack).to(haveResourceLike('AWS::Events::EventBusPolicy', { 'Action': 'events:PutEvents', 'StatementId': `Allow-account-${sourceAccount}`, diff --git a/packages/@aws-cdk/aws-glue/lib/table.ts b/packages/@aws-cdk/aws-glue/lib/table.ts index 3ed844d2d600a..c8a13826295d4 100644 --- a/packages/@aws-cdk/aws-glue/lib/table.ts +++ b/packages/@aws-cdk/aws-glue/lib/table.ts @@ -284,7 +284,7 @@ export class Table extends Resource implements ITable { resource: 'table', resourceName: `${this.database.databaseName}/${this.tableName}`, }); - this.node.defaultChild = tableResource; + this.construct.defaultChild = tableResource; } /** diff --git a/packages/@aws-cdk/aws-glue/test/table.test.ts b/packages/@aws-cdk/aws-glue/test/table.test.ts index a35d48e3d93dd..5989bd075120d 100644 --- a/packages/@aws-cdk/aws-glue/test/table.test.ts +++ b/packages/@aws-cdk/aws-glue/test/table.test.ts @@ -220,7 +220,7 @@ test('compressed table', () => { }); -test('table.node.defaultChild', () => { +test('table.construct.defaultChild', () => { // GIVEN const stack = new cdk.Stack(); const database = new glue.Database(stack, 'Database', { @@ -240,7 +240,7 @@ test('table.node.defaultChild', () => { }); // THEN - ok(table.node.defaultChild instanceof glue.CfnTable); + ok(table.construct.defaultChild instanceof glue.CfnTable); }); test('encrypted table: SSE-S3', () => { diff --git a/packages/@aws-cdk/aws-iam/lib/grant.ts b/packages/@aws-cdk/aws-iam/lib/grant.ts index c0cb065f7ee2c..d533ea2c3902d 100644 --- a/packages/@aws-cdk/aws-iam/lib/grant.ts +++ b/packages/@aws-cdk/aws-iam/lib/grant.ts @@ -263,11 +263,11 @@ export class Grant implements cdk.IDependable { /** * Make sure this grant is applied before the given constructs are deployed * - * The same as construct.node.addDependency(grant), but slightly nicer to read. + * The same as construct.construct.addDependency(grant), but slightly nicer to read. */ public applyBefore(...constructs: cdk.IConstruct[]) { for (const construct of constructs) { - construct.node.addDependency(this); + construct.construct.addDependency(this); } } } diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index 23cde93dc101c..dd5855242bb7e 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -417,7 +417,7 @@ export class Role extends Resource implements IRole { */ public withoutPolicyUpdates(): IRole { if (!this.immutableRole) { - this.immutableRole = new ImmutableRole(this.node.scope as Construct, `ImmutableRole${this.node.id}`, this); + this.immutableRole = new ImmutableRole(this.construct.scope as Construct, `ImmutableRole${this.construct.id}`, this); } return this.immutableRole; diff --git a/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts b/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts index da30dbf08227e..2486ff9f9bd60 100644 --- a/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts +++ b/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts @@ -34,13 +34,13 @@ export class UnknownPrincipal implements IPrincipal { } public get policyFragment(): PrincipalPolicyFragment { - throw new Error(`Cannot get policy fragment of ${this.resource.node.path}, resource imported without a role`); + throw new Error(`Cannot get policy fragment of ${this.resource.construct.path}, resource imported without a role`); } public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { const stack = Stack.of(this.resource); const repr = JSON.stringify(stack.resolve(statement)); - this.resource.node.addWarning(`Add statement to this resource's role: ${repr}`); + this.resource.construct.addWarning(`Add statement to this resource's role: ${repr}`); // Pretend we did the work. The human will do it for us, eventually. return { statementAdded: true, policyDependable: new ConcreteDependable() }; } diff --git a/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts b/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts index 4aa2ce2e9ddb8..847120c86d05b 100644 --- a/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts +++ b/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts @@ -14,7 +14,7 @@ describe('IAM escape hatches', () => { userName: 'MyUserName', }); - const cfn = user.node.findChild('Resource') as iam.CfnUser; + const cfn = user.construct.findChild('Resource') as iam.CfnUser; cfn.addPropertyOverride('UserName', 'OverriddenUserName'); expect(stack).toMatchTemplate({ @@ -33,7 +33,7 @@ describe('IAM escape hatches', () => { // GIVEN const stack = new Stack(); const user = new iam.User(stack, 'user', { userName: 'MyUserName' }); - const cfn = user.node.findChild('Resource') as iam.CfnUser; + const cfn = user.construct.findChild('Resource') as iam.CfnUser; // WHEN cfn.addPropertyOverride('Hello.World', 'Boom'); @@ -58,7 +58,7 @@ describe('IAM escape hatches', () => { // GIVEN const stack = new Stack(); const user = new iam.User(stack, 'user', { userName: 'MyUserName' }); - const cfn = user.node.findChild('Resource') as iam.CfnUser; + const cfn = user.construct.findChild('Resource') as iam.CfnUser; cfn.cfnOptions.updatePolicy = { useOnlineResharding: true }; // WHEN diff --git a/packages/@aws-cdk/aws-iam/test/policy.test.ts b/packages/@aws-cdk/aws-iam/test/policy.test.ts index 5bd50db9fd64f..9c85bf9d7e56c 100644 --- a/packages/@aws-cdk/aws-iam/test/policy.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy.test.ts @@ -262,7 +262,7 @@ describe('IAM policy', () => { }); // WHEN - res.node.addDependency(pol); + res.construct.addDependency(pol); // THEN expect(stack).toMatchTemplate({ @@ -288,7 +288,7 @@ describe('IAM policy', () => { }); // WHEN - res.node.addDependency(pol); + res.construct.addDependency(pol); // THEN expect(stack).toHaveResource('Some::Resource', { @@ -325,7 +325,7 @@ describe('IAM policy', () => { function createPolicyWithLogicalId(stack: Stack, logicalId: string): void { const policy = new Policy(stack, logicalId); - const cfnPolicy = policy.node.defaultChild as CfnPolicy; + const cfnPolicy = policy.construct.defaultChild as CfnPolicy; cfnPolicy.overrideLogicalId(logicalId); // force a particular logical ID // add statements & principal to satisfy validation diff --git a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts index 295cae174fe6a..5a18d395ac32f 100644 --- a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts +++ b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts @@ -535,7 +535,7 @@ function somePolicy(policyStack: Stack, policyName: string) { const someRole = new Role(policyStack, 'SomeExampleRole', { assumedBy: new AnyPrincipal(), }); - const roleResource = someRole.node.defaultChild as CfnElement; + const roleResource = someRole.construct.defaultChild as CfnElement; roleResource.overrideLogicalId('SomeRole'); // force a particular logical ID in the Ref expression return new Policy(policyStack, 'MyPolicy', { diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index 31650f4c9da63..ce53655e4abf0 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -299,7 +299,7 @@ export class Stream extends StreamBase { if (!props.encryption && !props.encryptionKey) { const conditionName = 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions'; - const existing = Stack.of(this).node.tryFindChild(conditionName); + const existing = Stack.of(this).construct.tryFindChild(conditionName); // create a single condition for the Stack if (!existing) { @@ -338,7 +338,7 @@ export class Stream extends StreamBase { if (encryptionType === StreamEncryption.KMS) { const encryptionKey = props.encryptionKey || new kms.Key(this, 'Key', { - description: `Created by ${this.node.path}`, + description: `Created by ${this.construct.path}`, }); const streamEncryption: CfnStream.StreamEncryptionProperty = { diff --git a/packages/@aws-cdk/aws-kms/test/test.key.ts b/packages/@aws-cdk/aws-kms/test/test.key.ts index a428ea1c05f73..56d33990415ba 100644 --- a/packages/@aws-cdk/aws-kms/test/test.key.ts +++ b/packages/@aws-cdk/aws-kms/test/test.key.ts @@ -160,9 +160,9 @@ export = { p.addArnPrincipal('arn'); key.addToResourcePolicy(p); - key.node.applyAspect(new Tag('tag1', 'value1')); - key.node.applyAspect(new Tag('tag2', 'value2')); - key.node.applyAspect(new Tag('tag3', '')); + key.construct.applyAspect(new Tag('tag1', 'value1')); + key.construct.applyAspect(new Tag('tag2', 'value2')); + key.construct.applyAspect(new Tag('tag3', '')); expect(stack).to(exactlyMatchTemplate({ Resources: { diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/api.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/api.ts index 2f3f3bcdc15fb..98baa1d8fb472 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/api.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/api.ts @@ -10,9 +10,9 @@ export class ApiEventSource implements lambda.IEventSource { } public bind(target: lambda.IFunction): void { - const id = `${target.node.uniqueId}:ApiEventSourceA7A86A4F`; + const id = `${target.construct.uniqueId}:ApiEventSourceA7A86A4F`; const stack = Stack.of(target); - let api = stack.node.tryFindChild(id) as apigw.RestApi; + let api = stack.construct.tryFindChild(id) as apigw.RestApi; if (!api) { api = new apigw.RestApi(stack, id, { defaultIntegration: new apigw.LambdaIntegration(target), diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts index ce9a3d8a5c998..c85ced6106ebf 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts @@ -21,10 +21,10 @@ export class DynamoEventSource extends StreamEventSource { public bind(target: lambda.IFunction) { if (!this.table.tableStreamArn) { - throw new Error(`DynamoDB Streams must be enabled on the table ${this.table.node.path}`); + throw new Error(`DynamoDB Streams must be enabled on the table ${this.table.construct.path}`); } - const eventSourceMapping = target.addEventSourceMapping(`DynamoDBEventSource:${this.table.node.uniqueId}`, + const eventSourceMapping = target.addEventSourceMapping(`DynamoDBEventSource:${this.table.construct.uniqueId}`, this.enrichMappingOptions({eventSourceArn: this.table.tableStreamArn}), ); this._eventSourceMappingId = eventSourceMapping.eventSourceMappingId; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/kinesis.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/kinesis.ts index 1a2de4c390155..dcfc8235e80eb 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/kinesis.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/kinesis.ts @@ -23,7 +23,7 @@ export class KinesisEventSource extends StreamEventSource { } public bind(target: lambda.IFunction) { - const eventSourceMapping = target.addEventSourceMapping(`KinesisEventSource:${this.stream.node.uniqueId}`, + const eventSourceMapping = target.addEventSourceMapping(`KinesisEventSource:${this.stream.construct.uniqueId}`, this.enrichMappingOptions({eventSourceArn: this.stream.streamArn}), ); this._eventSourceMappingId = eventSourceMapping.eventSourceMappingId; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts index 9badef3e6f8bc..148fd359a6295 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts @@ -27,7 +27,7 @@ export class SqsEventSource implements lambda.IEventSource { } public bind(target: lambda.IFunction) { - const eventSourceMapping = target.addEventSourceMapping(`SqsEventSource:${this.queue.node.uniqueId}`, { + const eventSourceMapping = target.addEventSourceMapping(`SqsEventSource:${this.queue.construct.uniqueId}`, { batchSize: this.props.batchSize, eventSourceArn: this.queue.queueArn, }); diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index 31f6eeab09f3f..ea2b13454ad18 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -309,8 +309,8 @@ export abstract class FunctionBase extends Resource implements IFunction { } public configureAsyncInvoke(options: EventInvokeConfigOptions): void { - if (this.node.tryFindChild('EventInvokeConfig') !== undefined) { - throw new Error(`An EventInvokeConfig has already been configured for the function at ${this.node.path}`); + if (this.construct.tryFindChild('EventInvokeConfig') !== undefined) { + throw new Error(`An EventInvokeConfig has already been configured for the function at ${this.construct.path}`); } new EventInvokeConfig(this, 'EventInvokeConfig', { @@ -368,8 +368,8 @@ export abstract class QualifiedFunctionBase extends FunctionBase { } public configureAsyncInvoke(options: EventInvokeConfigOptions): void { - if (this.node.tryFindChild('EventInvokeConfig') !== undefined) { - throw new Error(`An EventInvokeConfig has already been configured for the qualified function at ${this.node.path}`); + if (this.construct.tryFindChild('EventInvokeConfig') !== undefined) { + throw new Error(`An EventInvokeConfig has already been configured for the qualified function at ${this.construct.path}`); } new EventInvokeConfig(this, 'EventInvokeConfig', { diff --git a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts index fcc7cb4b75e2f..e3e069e5fa7bc 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts @@ -5,7 +5,7 @@ import { Function as LambdaFunction } from './function'; export function calculateFunctionHash(fn: LambdaFunction) { const stack = Stack.of(fn); - const functionResource = fn.node.defaultChild as CfnResource; + const functionResource = fn.construct.defaultChild as CfnResource; // render the cloudformation resource from this function const config = stack.resolve((functionResource as any)._toCloudFormation()); diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 5d0fd05c00b17..bee7d8287ce81 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -344,7 +344,7 @@ export class Function extends FunctionBase { // override the version's logical ID with a lazy string which includes the // hash of the function itself, so a new version resource is created when // the function configuration changes. - const cfn = this._currentVersion.node.defaultChild as CfnResource; + const cfn = this._currentVersion.construct.defaultChild as CfnResource; const originalLogicalId = this.stack.resolve(cfn.logicalId) as string; cfn.overrideLogicalId(Lazy.stringValue({ produce: _ => { @@ -604,7 +604,7 @@ export class Function extends FunctionBase { reservedConcurrentExecutions: props.reservedConcurrentExecutions, }); - resource.node.addDependency(this.role); + resource.construct.addDependency(this.role); this.functionName = this.getResourceNameAttribute(resource.ref); this.functionArn = this.getResourceArnAttribute(resource.attrArn, { @@ -652,7 +652,7 @@ export class Function extends FunctionBase { if (props.filesystem) { const config = props.filesystem.config; if (config.dependency) { - this.node.addDependency(...config.dependency); + this.construct.addDependency(...config.dependency); } resource.addPropertyOverride('FileSystemConfigs', @@ -755,7 +755,7 @@ export class Function extends FunctionBase { logGroupName: `/aws/lambda/${this.functionName}`, retention: logs.RetentionDays.INFINITE, }); - this._logGroup = logs.LogGroup.fromLogGroupArn(this, `${this.node.id}-LogGroup`, logretention.logGroupArn); + this._logGroup = logs.LogGroup.fromLogGroupArn(this, `${this.construct.id}-LogGroup`, logretention.logGroupArn); } return this._logGroup; } @@ -814,7 +814,7 @@ export class Function extends FunctionBase { } else { const securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, - description: 'Automatic security group for Lambda Function ' + this.node.uniqueId, + description: 'Automatic security group for Lambda Function ' + this.construct.uniqueId, allowAllOutbound: props.allowAllOutbound, }); securityGroups = [securityGroup]; diff --git a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts index f8515dc84e841..379a1aac981f6 100644 --- a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts @@ -70,7 +70,7 @@ export class SingletonFunction extends FunctionBase { * as a singleton across the stack. Use this method instead to declare dependencies. */ public addDependency(...up: cdk.IDependable[]) { - this.lambdaFunction.node.addDependency(...up); + this.lambdaFunction.construct.addDependency(...up); } /** @@ -78,7 +78,7 @@ export class SingletonFunction extends FunctionBase { * node.addDependency(). Use this method instead to declare this as a dependency of another construct. */ public dependOn(down: cdk.IConstruct) { - down.node.addDependency(this.lambdaFunction); + down.construct.addDependency(this.lambdaFunction); } /** @@ -91,7 +91,7 @@ export class SingletonFunction extends FunctionBase { private ensureLambda(props: SingletonFunctionProps): IFunction { const constructName = (props.lambdaPurpose || 'SingletonLambda') + slugify(props.uuid); - const existing = cdk.Stack.of(this).node.tryFindChild(constructName); + const existing = cdk.Stack.of(this).construct.tryFindChild(constructName); if (existing) { // Just assume this is true return existing as FunctionBase; diff --git a/packages/@aws-cdk/aws-lambda/test/test.code.ts b/packages/@aws-cdk/aws-lambda/test/test.code.ts index 354771c697a0c..408ec9d00ca79 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.code.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.code.ts @@ -62,7 +62,7 @@ export = { 'adds code asset metadata'(test: Test) { // GIVEN const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); + stack.construct.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); const location = path.join(__dirname, 'my-lambda-handler'); diff --git a/packages/@aws-cdk/aws-lambda/test/test.layers.ts b/packages/@aws-cdk/aws-lambda/test/test.layers.ts index 9a1b2664aa268..b12cab6465653 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.layers.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.layers.ts @@ -77,7 +77,7 @@ export = testCase({ 'asset metadata is added to the cloudformation resource'(test: Test) { // GIVEN const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); + stack.construct.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); // WHEN new lambda.LayerVersion(stack, 'layer', { diff --git a/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts b/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts index e4f57f5d4b33f..1ea3ef56dcfeb 100644 --- a/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts +++ b/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts @@ -14,7 +14,7 @@ export class KinesisDestination implements logs.ILogSubscriptionDestination { // Following example from https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#DestinationKinesisExample // Create a role to be assumed by CWL that can write to this stream and pass itself. const id = 'CloudWatchLogsCanPutRecords'; - const role = scope.node.tryFindChild(id) as iam.IRole || new iam.Role(scope, id, { + const role = scope.construct.tryFindChild(id) as iam.IRole || new iam.Role(scope, id, { assumedBy: new iam.ServicePrincipal('logs.amazonaws.com'), }); this.stream.grantWrite(role); diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index 2318fb1d9762e..de2a56950ece0 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -341,7 +341,7 @@ export class DatabaseCluster extends DatabaseClusterBase { // Cannot test whether the subnets are in different AZs, but at least we can test the amount. if (subnetIds.length < 2) { - this.node.addError(`Cluster requires at least 2 subnets, got ${subnetIds.length}`); + this.construct.addError(`Cluster requires at least 2 subnets, got ${subnetIds.length}`); } const subnetGroup = new CfnDBSubnetGroup(this, 'Subnets', { @@ -520,7 +520,7 @@ export class DatabaseCluster extends DatabaseClusterBase { // We must have a dependency on the NAT gateway provider here to create // things in the right order. - instance.node.addDependency(internetConnected); + instance.construct.addDependency(internetConnected); this.instanceIdentifiers.push(instance.ref); this.instanceEndpoints.push(new Endpoint(instance.attrEndpointAddress, portAttribute)); @@ -542,7 +542,7 @@ export class DatabaseCluster extends DatabaseClusterBase { } const id = 'RotationSingleUser'; - const existing = this.node.tryFindChild(id); + const existing = this.construct.tryFindChild(id); if (existing) { throw new Error('A single user rotation was already added to this cluster.'); } diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index 0890b26b705d2..6550222ac538d 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -503,12 +503,12 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData const { subnetIds } = props.vpc.selectSubnets(props.vpcPlacement); const subnetGroup = new CfnDBSubnetGroup(this, 'SubnetGroup', { - dbSubnetGroupDescription: `Subnet group for ${this.node.id} database`, + dbSubnetGroupDescription: `Subnet group for ${this.construct.id} database`, subnetIds, }); const securityGroups = props.securityGroups || [new ec2.SecurityGroup(this, 'SecurityGroup', { - description: `Security group for ${this.node.id} database`, + description: `Security group for ${this.construct.id} database`, vpc: props.vpc, })]; @@ -704,7 +704,7 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa } const id = 'RotationSingleUser'; - const existing = this.node.tryFindChild(id); + const existing = this.construct.tryFindChild(id); if (existing) { throw new Error('A single user rotation was already added to this instance.'); } diff --git a/packages/@aws-cdk/aws-rds/lib/proxy.ts b/packages/@aws-cdk/aws-rds/lib/proxy.ts index eff37a0b4307c..970ffcade1ac9 100644 --- a/packages/@aws-cdk/aws-rds/lib/proxy.ts +++ b/packages/@aws-cdk/aws-rds/lib/proxy.ts @@ -69,9 +69,9 @@ export class ProxyTarget { if (this.dbCluster && this.dbInstance) { throw new Error('Proxy cannot target both database cluster and database instance.'); } else if (this.dbCluster) { - engine = (this.dbCluster.node.defaultChild as CfnDBCluster).engine; + engine = (this.dbCluster.construct.defaultChild as CfnDBCluster).engine; } else if (this.dbInstance) { - engine = (this.dbInstance.node.defaultChild as CfnDBInstance).engine; + engine = (this.dbInstance.construct.defaultChild as CfnDBInstance).engine; } let engineFamily; diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster.ts b/packages/@aws-cdk/aws-rds/test/test.cluster.ts index 85d2a6d2b75d4..da015de8a5862 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/test.cluster.ts @@ -1114,6 +1114,6 @@ export = { function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' }}); - stack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + stack.construct.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); return stack; } diff --git a/packages/@aws-cdk/aws-redshift/lib/cluster.ts b/packages/@aws-cdk/aws-redshift/lib/cluster.ts index 48caa7aabf1db..489047df1b067 100644 --- a/packages/@aws-cdk/aws-redshift/lib/cluster.ts +++ b/packages/@aws-cdk/aws-redshift/lib/cluster.ts @@ -505,7 +505,7 @@ export class Cluster extends ClusterBase { } const id = 'RotationSingleUser'; - const existing = this.node.tryFindChild(id); + const existing = this.construct.tryFindChild(id); if (existing) { throw new Error('A single user rotation was already added to this cluster.'); } diff --git a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts index 385a2f53208b5..7984b6877e97f 100644 --- a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts @@ -324,6 +324,6 @@ test('throws when trying to add single user rotation multiple times', () => { function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); - stack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + stack.construct.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); return stack; } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53-targets/lib/cloudfront-target.ts b/packages/@aws-cdk/aws-route53-targets/lib/cloudfront-target.ts index 217ba72cfc079..c78c599a0c492 100644 --- a/packages/@aws-cdk/aws-route53-targets/lib/cloudfront-target.ts +++ b/packages/@aws-cdk/aws-route53-targets/lib/cloudfront-target.ts @@ -22,7 +22,7 @@ export class CloudFrontTarget implements route53.IAliasRecordTarget { const scopeStack = Stack.of(scope); let mapping = - (scopeStack.node.tryFindChild(mappingName) as CfnMapping) ?? + (scopeStack.construct.tryFindChild(mappingName) as CfnMapping) ?? new CfnMapping(scopeStack, mappingName, { mapping: { ['aws']: { diff --git a/packages/@aws-cdk/aws-route53-targets/lib/interface-vpc-endpoint-target.ts b/packages/@aws-cdk/aws-route53-targets/lib/interface-vpc-endpoint-target.ts index 40b0902cd236a..f01a8843bcf9e 100644 --- a/packages/@aws-cdk/aws-route53-targets/lib/interface-vpc-endpoint-target.ts +++ b/packages/@aws-cdk/aws-route53-targets/lib/interface-vpc-endpoint-target.ts @@ -8,7 +8,7 @@ import * as cdk from '@aws-cdk/core'; export class InterfaceVpcEndpointTarget implements route53.IAliasRecordTarget { private readonly cfnVpcEndpoint: ec2.CfnVPCEndpoint; constructor(private readonly vpcEndpoint: ec2.IInterfaceVpcEndpoint) { - this.cfnVpcEndpoint = this.vpcEndpoint.node.findChild('Resource') as ec2.CfnVPCEndpoint; + this.cfnVpcEndpoint = this.vpcEndpoint.construct.findChild('Resource') as ec2.CfnVPCEndpoint; } public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig { diff --git a/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts b/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts index 98778fe9d5107..93d28fe930bef 100644 --- a/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts +++ b/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts @@ -32,7 +32,7 @@ export = { const stack2 = new cdk.Stack(undefined, 'TestStack', { env: { account: '12345', region: 'us-east-1' }, }); - stack2.node.setContext(missing[0].key, fakeZone); + stack2.construct.setContext(missing[0].key, fakeZone); // WHEN const zoneRef = HostedZone.fromLookup(stack2, 'MyZoneProvider', filter); @@ -70,7 +70,7 @@ export = { const stack2 = new cdk.Stack(undefined, 'TestStack', { env: { account: '12345', region: 'us-east-1' }, }); - stack2.node.setContext(missing[0].key, fakeZone); + stack2.construct.setContext(missing[0].key, fakeZone); const zone = HostedZone.fromLookup(stack2, 'MyZoneProvider', filter); diff --git a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts index e457de127d442..63f4b3750b990 100644 --- a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts +++ b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts @@ -176,7 +176,7 @@ export class Asset extends cdk.Construct implements cdk.IAsset { * (e.g. "Code" for AWS::Lambda::Function) */ public addResourceMetadata(resource: cdk.CfnResource, resourceProperty: string) { - if (!this.node.tryGetContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT)) { + if (!this.construct.tryGetContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT)) { return; // not enabled } diff --git a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts index d08005a39f692..7038155bde688 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts +++ b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts @@ -24,7 +24,7 @@ test('simple use case', () => { // verify that metadata contains an "aws:cdk:asset" entry with // the correct information - const entry = stack.node.metadata.find(m => m.type === 'aws:cdk:asset'); + const entry = stack.construct.metadata.find(m => m.type === 'aws:cdk:asset'); expect(entry).toBeTruthy(); // verify that now the template contains parameters for this asset @@ -74,7 +74,7 @@ test('"file" assets', () => { const stack = new cdk.Stack(); const filePath = path.join(__dirname, 'file-asset.txt'); new Asset(stack, 'MyAsset', { path: filePath }); - const entry = stack.node.metadata.find(m => m.type === 'aws:cdk:asset'); + const entry = stack.construct.metadata.find(m => m.type === 'aws:cdk:asset'); expect(entry).toBeTruthy(); // synthesize first so "prepare" is called @@ -196,7 +196,7 @@ test('isZipArchive indicates if the asset represents a .zip file (either explici test('addResourceMetadata can be used to add CFN metadata to resources', () => { // GIVEN const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); + stack.construct.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); const location = path.join(__dirname, 'sample-asset-directory'); const resource = new cdk.CfnResource(stack, 'MyResource', { type: 'My::Resource::Type' }); diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts index 6f0f877662891..ec06a5a66c31c 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts @@ -77,7 +77,7 @@ export class Source { } let id = 1; - while (scope.node.tryFindChild(`Asset${id}`)) { + while (scope.construct.tryFindChild(`Asset${id}`)) { id++; } const asset = new s3_assets.Asset(scope, `Asset${id}`, { diff --git a/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts b/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts index a1ea5ac5ac42c..5cfb1cc918841 100644 --- a/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts +++ b/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts @@ -11,7 +11,7 @@ export class LambdaDestination implements s3.IBucketNotificationDestination { } public bind(_scope: Construct, bucket: s3.IBucket): s3.BucketNotificationDestinationConfig { - const permissionId = `AllowBucketNotificationsFrom${bucket.node.uniqueId}`; + const permissionId = `AllowBucketNotificationsFrom${bucket.construct.uniqueId}`; if (this.fn.permissionsNode.tryFindChild(permissionId) === undefined) { this.fn.addPermission(permissionId, { diff --git a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts index cadf2609692f0..fefd5b4b68b62 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts @@ -39,7 +39,7 @@ test('when notification are added, a custom resource is provisioned + a lambda h test('when notification are added, you can tag the lambda', () => { const stack = new cdk.Stack(); - stack.node.applyAspect(new cdk.Tag('Lambda', 'AreTagged')); + stack.construct.applyAspect(new cdk.Tag('Lambda', 'AreTagged')); const bucket = new s3.Bucket(stack, 'MyBucket'); diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index acb1949b1cb2e..523b93bb84f71 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -1425,7 +1425,7 @@ export class Bucket extends BucketBase { if (encryptionType === BucketEncryption.KMS) { const encryptionKey = props.encryptionKey || new kms.Key(this, 'Key', { - description: `Created by ${this.node.path}`, + description: `Created by ${this.construct.path}`, }); const bucketEncryption = { @@ -1623,7 +1623,7 @@ export class Bucket extends BucketBase { return this.inventories.map((inventory, index) => { const format = inventory.format ?? InventoryFormat.CSV; const frequency = inventory.frequency ?? InventoryFrequency.WEEKLY; - const id = inventory.inventoryId ?? `${this.node.id}Inventory${index}`; + const id = inventory.inventoryId ?? `${this.construct.id}Inventory${index}`; if (inventory.destination.bucket instanceof Bucket) { inventory.destination.bucket.addToResourcePolicy(new iam.PolicyStatement({ diff --git a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts index 4ceced2e93e2d..1403ddcb2e7b4 100644 --- a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts +++ b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts @@ -30,7 +30,7 @@ export class NotificationsResourceHandler extends cdk.Construct { // well-known logical id to ensure stack singletonity const logicalId = 'BucketNotificationsHandler050a0587b7544547bf325f094a3db834'; - let lambda = root.node.tryFindChild(logicalId) as NotificationsResourceHandler; + let lambda = root.construct.tryFindChild(logicalId) as NotificationsResourceHandler; if (!lambda) { lambda = new NotificationsResourceHandler(root, logicalId); } @@ -83,7 +83,7 @@ export class NotificationsResourceHandler extends cdk.Construct { }, }); - resource.node.addDependency(role); + resource.construct.addDependency(role); this.functionArn = resource.getAtt('Arn').toString(); } diff --git a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts index fc5d83f8106d7..99de445c4977c 100644 --- a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts +++ b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts @@ -63,7 +63,7 @@ export class BucketNotifications extends cdk.Construct { // for example, the SNS topic policy must be created /before/ the notification resource. // otherwise, S3 won't be able to confirm the subscription. if (targetProps.dependencies) { - resource.node.addDependency(...targetProps.dependencies); + resource.construct.addDependency(...targetProps.dependencies); } // based on the target type, add the the correct configurations array diff --git a/packages/@aws-cdk/aws-s3/test/test.aspect.ts b/packages/@aws-cdk/aws-s3/test/test.aspect.ts index ba2049b0f993e..8a74ff3b1cc7c 100644 --- a/packages/@aws-cdk/aws-s3/test/test.aspect.ts +++ b/packages/@aws-cdk/aws-s3/test/test.aspect.ts @@ -11,7 +11,7 @@ export = { new s3.Bucket(stack, 'MyBucket'); // WHEN - stack.node.applyAspect(new BucketVersioningChecker()); + stack.construct.applyAspect(new BucketVersioningChecker()); // THEN const assembly = SynthUtils.synthesize(stack); @@ -29,7 +29,7 @@ export = { }); // WHEN - stack.node.applyAspect(new BucketVersioningChecker()); + stack.construct.applyAspect(new BucketVersioningChecker()); // THEN const assembly = SynthUtils.synthesize(stack); @@ -44,7 +44,7 @@ class BucketVersioningChecker implements cdk.IAspect { if (node instanceof s3.CfnBucket) { if (!node.versioningConfiguration || (!cdk.Tokenization.isResolvable(node.versioningConfiguration) && node.versioningConfiguration.status !== 'Enabled')) { - node.node.addError('Bucket versioning is not enabled'); + node.construct.addError('Bucket versioning is not enabled'); } } } diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts index 16ff1056534bc..7c87816854a86 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts @@ -211,7 +211,7 @@ export class SecretRotation extends Construct { } // Max length of 64 chars, get the last 64 chars - const uniqueId = this.node.uniqueId; + const uniqueId = this.construct.uniqueId; const rotationFunctionName = uniqueId.substring(Math.max(uniqueId.length - 64, 0), uniqueId.length); const securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index 1a256fb66aefd..4ca105f58d59a 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -315,7 +315,7 @@ export class Secret extends SecretBase { */ public attach(target: ISecretAttachmentTarget): ISecret { const id = 'Attachment'; - const existing = this.node.tryFindChild(id); + const existing = this.construct.tryFindChild(id); if (existing) { throw new Error('Secret is already attached to a target.'); diff --git a/packages/@aws-cdk/aws-servicediscovery/lib/alias-target-instance.ts b/packages/@aws-cdk/aws-servicediscovery/lib/alias-target-instance.ts index 2e9eb90f105d6..defbf3a1cd87c 100644 --- a/packages/@aws-cdk/aws-servicediscovery/lib/alias-target-instance.ts +++ b/packages/@aws-cdk/aws-servicediscovery/lib/alias-target-instance.ts @@ -65,7 +65,7 @@ export class AliasTargetInstance extends InstanceBase { AWS_ALIAS_DNS_NAME: props.dnsName, ...props.customAttributes, }, - instanceId: props.instanceId || this.node.uniqueId, + instanceId: props.instanceId || this.construct.uniqueId, serviceId: props.service.serviceId, }); diff --git a/packages/@aws-cdk/aws-servicediscovery/lib/instance.ts b/packages/@aws-cdk/aws-servicediscovery/lib/instance.ts index 00e7d6a126934..c7567de4c8bc8 100644 --- a/packages/@aws-cdk/aws-servicediscovery/lib/instance.ts +++ b/packages/@aws-cdk/aws-servicediscovery/lib/instance.ts @@ -50,7 +50,7 @@ export abstract class InstanceBase extends Resource implements IInstance { */ protected uniqueInstanceId() { // Max length of 64 chars, get the last 64 chars - const id = this.node.uniqueId; + const id = this.construct.uniqueId; return id.substring(Math.max(id.length - 64, 0), id.length); } } diff --git a/packages/@aws-cdk/aws-ses-actions/lib/lambda.ts b/packages/@aws-cdk/aws-ses-actions/lib/lambda.ts index 3fa7d418e2ac4..b819672bc4755 100644 --- a/packages/@aws-cdk/aws-ses-actions/lib/lambda.ts +++ b/packages/@aws-cdk/aws-ses-actions/lib/lambda.ts @@ -68,10 +68,10 @@ export class Lambda implements ses.IReceiptRuleAction { // Ensure permission is deployed before rule const permission = this.props.function.permissionsNode.tryFindChild(permissionId) as lambda.CfnPermission; if (permission) { // The Lambda could be imported - rule.node.addDependency(permission); + rule.construct.addDependency(permission); } else { // eslint-disable-next-line max-len - rule.node.addWarning('This rule is using a Lambda action with an imported function. Ensure permission is given to SES to invoke that function.'); + rule.construct.addWarning('This rule is using a Lambda action with an imported function. Ensure permission is given to SES to invoke that function.'); } return { diff --git a/packages/@aws-cdk/aws-ses-actions/lib/s3.ts b/packages/@aws-cdk/aws-ses-actions/lib/s3.ts index 24c8590511701..2e4129690fd80 100644 --- a/packages/@aws-cdk/aws-ses-actions/lib/s3.ts +++ b/packages/@aws-cdk/aws-ses-actions/lib/s3.ts @@ -61,11 +61,11 @@ export class S3 implements ses.IReceiptRuleAction { }); this.props.bucket.addToResourcePolicy(s3Statement); - const policy = this.props.bucket.node.tryFindChild('Policy') as s3.BucketPolicy; + const policy = this.props.bucket.construct.tryFindChild('Policy') as s3.BucketPolicy; if (policy) { // The bucket could be imported - rule.node.addDependency(policy); + rule.construct.addDependency(policy); } else { - rule.node.addWarning('This rule is using a S3 action with an imported bucket. Ensure permission is given to SES to write to that bucket.'); + rule.construct.addWarning('This rule is using a S3 action with an imported bucket. Ensure permission is given to SES to write to that bucket.'); } // Allow SES to use KMS master key diff --git a/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts b/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts index 943813184ed1f..50bb1883777ec 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts @@ -27,14 +27,14 @@ export class LambdaSubscription implements sns.ITopicSubscription { throw new Error('The supplied lambda Function object must be an instance of Construct'); } - this.fn.addPermission(`AllowInvoke:${topic.node.uniqueId}`, { + this.fn.addPermission(`AllowInvoke:${topic.construct.uniqueId}`, { sourceArn: topic.topicArn, principal: new iam.ServicePrincipal('sns.amazonaws.com'), }); return { subscriberScope: this.fn, - subscriberId: topic.node.id, + subscriberId: topic.construct.id, endpoint: this.fn.functionArn, protocol: sns.SubscriptionProtocol.LAMBDA, filterPolicy: this.props.filterPolicy, diff --git a/packages/@aws-cdk/aws-sns-subscriptions/lib/sqs.ts b/packages/@aws-cdk/aws-sns-subscriptions/lib/sqs.ts index 39c8362d60c4f..7ff0c6921571b 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/lib/sqs.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/lib/sqs.ts @@ -48,7 +48,7 @@ export class SqsSubscription implements sns.ITopicSubscription { return { subscriberScope: this.queue, - subscriberId: topic.node.uniqueId, + subscriberId: topic.construct.uniqueId, endpoint: this.queue.queueArn, protocol: sns.SubscriptionProtocol.SQS, rawMessageDelivery: this.props.rawMessageDelivery, diff --git a/packages/@aws-cdk/aws-sns/lib/topic-base.ts b/packages/@aws-cdk/aws-sns/lib/topic-base.ts index 07b96a34629d2..84fee88c6821a 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic-base.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic-base.ts @@ -73,8 +73,8 @@ export abstract class TopicBase extends Resource implements ITopic { // We use the subscriber's id as the construct id. There's no meaning // to subscribing the same subscriber twice on the same topic. - if (scope.node.tryFindChild(id)) { - throw new Error(`A subscription with id "${id}" already exists under the scope ${scope.node.path}`); + if (scope.construct.tryFindChild(id)) { + throw new Error(`A subscription with id "${id}" already exists under the scope ${scope.construct.path}`); } new Subscription(scope, id, { @@ -125,8 +125,8 @@ export abstract class TopicBase extends Resource implements ITopic { const re = /TokenSubscription:([\d]*)/gm; // Search through the construct and all of its children // for previous subscriptions that match our regex pattern - for (const source of scope.node.findAll()) { - const m = re.exec(source.node.id); // Use regex to find a match + for (const source of scope.construct.findAll()) { + const m = re.exec(source.construct.id); // Use regex to find a match if (m !== null) { // if we found a match const matchSuffix = parseInt(m[1], 10); // get the suffix for that match (as integer) if (matchSuffix >= nextSuffix) { // check if the match suffix is larger or equal to currently proposed suffix diff --git a/packages/@aws-cdk/aws-sqs/lib/queue.ts b/packages/@aws-cdk/aws-sqs/lib/queue.ts index d335da2c9120f..b8840e9c9af89 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue.ts @@ -302,7 +302,7 @@ export class Queue extends QueueBase { if (encryption === QueueEncryption.KMS) { const masterKey = props.encryptionMasterKey || new kms.Key(this, 'Key', { - description: `Created by ${this.node.path}`, + description: `Created by ${this.construct.path}`, }); return { diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index bc73278bfc267..27491975dd81f 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -390,7 +390,7 @@ export class StringParameter extends ParameterBase implements IStringParameter { public static valueForTypedStringParameter(scope: Construct, parameterName: string, type = ParameterType.STRING, version?: number): string { const stack = Stack.of(scope); const id = makeIdentityForImportedValue(parameterName); - const exists = stack.node.tryFindChild(id) as IStringParameter; + const exists = stack.construct.tryFindChild(id) as IStringParameter; if (exists) { return exists.stringValue; } @@ -406,7 +406,7 @@ export class StringParameter extends ParameterBase implements IStringParameter { public static valueForSecureStringParameter(scope: Construct, parameterName: string, version: number): string { const stack = Stack.of(scope); const id = makeIdentityForImportedValue(parameterName); - const exists = stack.node.tryFindChild(id) as IStringParameter; + const exists = stack.construct.tryFindChild(id) as IStringParameter; if (exists) { return exists.stringValue; } return this.fromSecureStringParameterAttributes(stack, id, { parameterName, version }).stringValue; diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter-arns.ts b/packages/@aws-cdk/aws-ssm/test/integ.parameter-arns.ts index 358d92abbce25..2fb19bd2a9367 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter-arns.ts +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter-arns.ts @@ -19,7 +19,7 @@ const params = [ ]; for (const p of params) { - new CfnOutput(stack, `${p.node.id}Arn`, { value: p.parameterArn }); + new CfnOutput(stack, `${p.construct.id}Arn`, { value: p.parameterArn }); } app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-ecs-task-base.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-ecs-task-base.ts index 12d1c71665577..b38efbf39865f 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-ecs-task-base.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-ecs-task-base.ts @@ -89,7 +89,7 @@ export class EcsRunTaskBase implements ec2.IConnectable, sfn.IStepFunctionsTask for (const override of this.props.containerOverrides || []) { const name = override.containerDefinition.containerName; if (!cdk.Token.isUnresolved(name)) { - const cont = this.props.taskDefinition.node.tryFindChild(name); + const cont = this.props.taskDefinition.construct.tryFindChild(name); if (!cont) { throw new Error(`Overrides mention container with name '${name}', but no such container in task definition`); } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-task.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-task.ts index d06d204641653..371fc65a461c6 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-task.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-task.ts @@ -260,7 +260,7 @@ export class EcsRunTask extends sfn.TaskStateBase implements ec2.IConnectable { for (const override of this.props.containerOverrides ?? []) { const name = override.containerDefinition.containerName; if (!cdk.Token.isUnresolved(name)) { - const cont = this.props.taskDefinition.node.tryFindChild(name); + const cont = this.props.taskDefinition.construct.tryFindChild(name); if (!cont) { throw new Error(`Overrides mention container with name '${name}', but no such container in task definition`); } diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/activity.ts b/packages/@aws-cdk/aws-stepfunctions/lib/activity.ts index ef97f45e6f8b3..5a011fbf0bd74 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/activity.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/activity.ts @@ -185,7 +185,7 @@ export class Activity extends Resource implements IActivity { } private generateName(): string { - const name = this.node.uniqueId; + const name = this.construct.uniqueId; if (name.length > 80) { return name.substring(0, 40) + name.substring(name.length - 40); } diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine-fragment.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine-fragment.ts index 929aed5b22219..5a9e8884d22b0 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine-fragment.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine-fragment.ts @@ -19,7 +19,7 @@ export abstract class StateMachineFragment extends cdk.Construct implements ICha public abstract readonly endStates: INextable[]; public get id() { - return this.node.id; + return this.construct.id; } /** diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts index a6632a7e5d35d..663f3346892fa 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts @@ -305,7 +305,7 @@ export class StateMachine extends StateMachineBase { loggingConfiguration, }); - resource.node.addDependency(this.role); + resource.construct.addDependency(this.role); for (const statement of graph.policyStatements) { this.addToRolePolicy(statement); diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts b/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts index d586a3e472d98..8c4701764c7cf 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts @@ -70,7 +70,7 @@ export abstract class State extends cdk.Construct implements IChainable { if (isPrefixable(el)) { el.addPrefix(prefix); } - queue.push(...el.node.children); + queue.push(...el.construct.children); } } @@ -186,7 +186,7 @@ export abstract class State extends cdk.Construct implements IChainable { } public get id() { - return this.node.id; + return this.construct.id; } /** diff --git a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts index 845aa001ba3d2..40625bd8b7b0a 100644 --- a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts @@ -297,7 +297,7 @@ describe('CDK Include', () => { const cfnTemplate = includeTestTemplate(stack, 'resource-attribute-depends-on.json'); const cfnBucket2 = cfnTemplate.getResource('Bucket2'); - expect(cfnBucket2.node.dependencies).toHaveLength(1); + expect(cfnBucket2.construct.dependencies).toHaveLength(1); // we always render dependsOn as an array, even if it's a single string expect(stack).toHaveResourceLike('AWS::S3::Bucket', { "Properties": { @@ -313,7 +313,7 @@ describe('CDK Include', () => { const cfnTemplate = includeTestTemplate(stack, 'resource-attribute-depends-on-array.json'); const cfnBucket2 = cfnTemplate.getResource('Bucket2'); - expect(cfnBucket2.node.dependencies).toHaveLength(2); + expect(cfnBucket2.construct.dependencies).toHaveLength(2); expect(stack).toHaveResourceLike('AWS::S3::Bucket', { "Properties": { "BucketName": "bucket2", diff --git a/packages/@aws-cdk/core/lib/annotations.ts b/packages/@aws-cdk/core/lib/annotations.ts index 8f13e09987035..a90ab995441a1 100644 --- a/packages/@aws-cdk/core/lib/annotations.ts +++ b/packages/@aws-cdk/core/lib/annotations.ts @@ -55,6 +55,6 @@ export class Annotations { * @param message The message itself */ private addMessage(level: string, message: string) { - this.scope.node.addMetadata(level, message); + this.scope.construct.addMetadata(level, message); } } \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/aspect.ts b/packages/@aws-cdk/core/lib/aspect.ts index 3bca67a12aa6d..8bf84d4d3f22f 100644 --- a/packages/@aws-cdk/core/lib/aspect.ts +++ b/packages/@aws-cdk/core/lib/aspect.ts @@ -45,7 +45,7 @@ export class Aspects { */ public add(aspect: IAspect) { // TODO(2.0): this._aspects.push(aspect); - this.scope.node._actualNode.applyAspect(aspect); + this.scope.construct._actualNode.applyAspect(aspect); } /** @@ -53,6 +53,6 @@ export class Aspects { */ public get aspects(): IAspect[] { // TODO(2.0): return [ ...this._aspects ]; - return [ ...(this.scope.node._actualNode as any)._aspects ]; // clone + return [ ...(this.scope.construct._actualNode as any)._aspects ]; // clone } } \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index 6b3832ecba636..572fa9f33fe8f 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -91,8 +91,8 @@ export class Construct extends constructs.Construct implements IConstruct { } Object.defineProperty(this, CONSTRUCT_SYMBOL, { value: true }); - this.node = ConstructNode._unwrap(constructs.Node.of(this)); - this.construct = this.node; + this.construct = ConstructNode._unwrap(constructs.Node.of(this)); + this.node = this.construct; const disableTrace = this.construct.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) || diff --git a/packages/@aws-cdk/core/lib/private/tree-metadata.ts b/packages/@aws-cdk/core/lib/private/tree-metadata.ts index 5ff0b2a2b2ded..5e87c96b027e1 100644 --- a/packages/@aws-cdk/core/lib/private/tree-metadata.ts +++ b/packages/@aws-cdk/core/lib/private/tree-metadata.ts @@ -33,7 +33,7 @@ export class TreeMetadata extends Construct { try { return visit(c); } catch (e) { - Annotations.of(this).addWarning(`Failed to render tree metadata for node [${c.node.id}]. Reason: ${e}`); + Annotations.of(this).addWarning(`Failed to render tree metadata for node [${c.construct.id}]. Reason: ${e}`); return undefined; } }); diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts index 01759f71b7e45..3c3d7d8c42568 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts @@ -147,7 +147,7 @@ export class Provider extends Construct implements cfn.ICustomResourceProvider { private createFunction(entrypoint: string) { const fn = new lambda.Function(this, `framework-${entrypoint}`, { code: lambda.Code.fromAsset(RUNTIME_HANDLER_PATH), - description: `AWS CDK resource provider framework - ${entrypoint} (${this.node.path})`.slice(0, 256), + description: `AWS CDK resource provider framework - ${entrypoint} (${this.construct.path})`.slice(0, 256), runtime: lambda.Runtime.NODEJS_10_X, handler: `framework.${entrypoint}`, timeout: FRAMEWORK_HANDLER_TIMEOUT, diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts index f35bce528d366..9672810518f71 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts @@ -87,7 +87,7 @@ export class WaiterStateMachine extends Construct { RoleArn: role.roleArn, }, }); - resource.node.addDependency(role); + resource.construct.addDependency(role); this.stateMachineArn = resource.ref; } diff --git a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.ts b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.ts index 3b241031e04c1..ddce585cb4a1b 100644 --- a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.ts +++ b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.ts @@ -33,7 +33,7 @@ const listTopics = new AwsCustomResource(stack, 'ListTopics', { }, policy: AwsCustomResourcePolicy.fromSdkCalls({resources: AwsCustomResourcePolicy.ANY_RESOURCE}), }); -listTopics.node.addDependency(topic); +listTopics.construct.addDependency(topic); const ssmParameter = new ssm.StringParameter(stack, 'DummyParameter', { stringValue: '1337', diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts index 01ccd37e89d89..6fe85db543230 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts @@ -30,7 +30,7 @@ class TestStack extends Stack { }); // delay file2 updates so we can test async assertions - file2.node.addDependency(file1); + file2.construct.addDependency(file1); new CfnOutput(this, 'file1-url', { value: file1.url }); new CfnOutput(this, 'file2-url', { value: file2.url }); diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-assert.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-assert.ts index 0823d21e05e51..4b06558fc1f8b 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-assert.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-assert.ts @@ -54,7 +54,7 @@ class S3AssertProvider extends Construct { public static getOrCreate(scope: Construct) { const providerId = 'com.amazonaws.cdk.custom-resources.s3assert-provider'; const stack = Stack.of(scope); - const group = stack.node.tryFindChild(providerId) as S3AssertProvider || new S3AssertProvider(stack, providerId); + const group = stack.construct.tryFindChild(providerId) as S3AssertProvider || new S3AssertProvider(stack, providerId); return group.provider.serviceToken; } diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts index 234ec567cbdbb..ca689a41df832 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts @@ -65,7 +65,7 @@ class S3FileProvider extends Construct { public static getOrCreate(scope: Construct) { const stack = Stack.of(scope); const id = 'com.amazonaws.cdk.custom-resources.s3file-provider'; - const x = stack.node.tryFindChild(id) as S3FileProvider || new S3FileProvider(stack, id); + const x = stack.construct.tryFindChild(id) as S3FileProvider || new S3FileProvider(stack, id); return x.provider.serviceToken; } diff --git a/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts b/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts index c13dad054c790..c22e99b13bd08 100644 --- a/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts +++ b/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts @@ -270,10 +270,10 @@ function roleFromPlaceholderArn(scope: Construct, arn: string | undefined): iam. scope = hackyRoleScope(scope, arn); // https://github.com/aws/aws-cdk/issues/7255 - let existingRole = scope.node.tryFindChild(`ImmutableRole${id}`) as iam.IRole; + let existingRole = scope.construct.tryFindChild(`ImmutableRole${id}`) as iam.IRole; if (existingRole) { return existingRole; } // For when #7255 is fixed. - existingRole = scope.node.tryFindChild(id) as iam.IRole; + existingRole = scope.construct.tryFindChild(id) as iam.IRole; if (existingRole) { return existingRole; } return iam.Role.fromRoleArn(scope, id, cfnExpressionFromManifestString(arn), { mutable: false }); diff --git a/packages/@aws-cdk/pipelines/lib/pipeline.ts b/packages/@aws-cdk/pipelines/lib/pipeline.ts index f20021b34d1a8..e565c0271881e 100644 --- a/packages/@aws-cdk/pipelines/lib/pipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/pipeline.ts @@ -65,7 +65,7 @@ export class CdkPipeline extends Construct { constructor(scope: Construct, id: string, props: CdkPipelineProps) { super(scope, id); - if (!App.isApp(this.node.root)) { + if (!App.isApp(this.construct.root)) { throw new Error('CdkPipeline must be created under an App'); } @@ -103,7 +103,7 @@ export class CdkPipeline extends Construct { projectName: maybeSuffix(props.pipelineName, '-publish'), }); - this.node.applyAspect({ visit: () => this._assets.removeAssetsStageIfEmpty() }); + this.construct.applyAspect({ visit: () => this._assets.removeAssetsStageIfEmpty() }); } /** @@ -195,7 +195,7 @@ export class CdkPipeline extends Construct { const depAction = stackActions.find(s => s.stackArtifactId === depId); if (depAction === undefined) { - this.node.addWarning(`Stack '${stackAction.stackName}' depends on stack ` + + this.construct.addWarning(`Stack '${stackAction.stackName}' depends on stack ` + `'${depId}', but that dependency is not deployed through the pipeline!`); } else if (!(depAction.executeRunOrder < stackAction.prepareRunOrder)) { yield `Stack '${stackAction.stackName}' depends on stack ` + diff --git a/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts b/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts index 7fc07f8d30fa5..83b40ae2fbdf2 100644 --- a/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts +++ b/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts @@ -6,10 +6,10 @@ import { App, IConstruct, Stage } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; export function appOf(construct: IConstruct): App { - const root = construct.node.root; + const root = construct.construct.root; if (!App.isApp(root)) { - throw new Error(`Construct must be created under an App, but is not: ${construct.node.path}`); + throw new Error(`Construct must be created under an App, but is not: ${construct.construct.path}`); } return root; diff --git a/packages/@aws-cdk/pipelines/lib/stage.ts b/packages/@aws-cdk/pipelines/lib/stage.ts index dd5aa28c5e50e..994c6f2097224 100644 --- a/packages/@aws-cdk/pipelines/lib/stage.ts +++ b/packages/@aws-cdk/pipelines/lib/stage.ts @@ -55,7 +55,7 @@ export class CdkStage extends Construct { this.cloudAssemblyArtifact = props.cloudAssemblyArtifact; this.host = props.host; - this.node.applyAspect({ visit: () => this.prepareStage() }); + this.construct.applyAspect({ visit: () => this.prepareStage() }); } /** diff --git a/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts b/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts index 71717c4dbb1a7..3e9f2d7b09c29 100644 --- a/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts +++ b/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts @@ -26,7 +26,7 @@ test('in a cross-account/cross-region setup, artifact bucket can be read by depl // THEN app.synth(); - const supportStack = app.node.findAll().filter(Stack.isStack).find(s => s.stackName === 'PipelineStack-support-us-elsewhere'); + const supportStack = app.construct.findAll().filter(Stack.isStack).find(s => s.stackName === 'PipelineStack-support-us-elsewhere'); expect(supportStack).not.toBeUndefined(); expect(supportStack).toHaveResourceLike('AWS::S3::BucketPolicy', { diff --git a/packages/decdk/lib/declarative-stack.ts b/packages/decdk/lib/declarative-stack.ts index 8b937ecd3525e..47b929861c66d 100644 --- a/packages/decdk/lib/declarative-stack.ts +++ b/packages/decdk/lib/declarative-stack.ts @@ -383,9 +383,9 @@ function invokeMethod(stack: cdk.Stack, method: reflect.Callable, parameters: an */ function deconstructGetAtt(stack: cdk.Stack, id: string, attribute: string) { return cdk.Lazy.stringValue({ produce: () => { - const res = stack.node.tryFindChild(id); + const res = stack.construct.tryFindChild(id); if (!res) { - const include = stack.node.tryFindChild('Include') as cdk.CfnInclude; + const include = stack.construct.tryFindChild('Include') as cdk.CfnInclude; if (!include) { throw new Error(`Unexpected - "Include" should be in the stack at this point`); } @@ -403,7 +403,7 @@ function deconstructGetAtt(stack: cdk.Stack, id: string, attribute: string) { } function findConstruct(stack: cdk.Stack, id: string) { - const child = stack.node.tryFindChild(id); + const child = stack.construct.tryFindChild(id); if (!child) { throw new Error(`Construct with ID ${id} not found (it must be defined before it is referenced)`); } @@ -411,7 +411,7 @@ function findConstruct(stack: cdk.Stack, id: string) { } function processReferences(stack: cdk.Stack) { - const include = stack.node.findChild('Include') as cdk.CfnInclude; + const include = stack.construct.findChild('Include') as cdk.CfnInclude; if (!include) { throw new Error('Unexpected'); } From d651948b4b4ef43fedbaba69905e860fd595513d Mon Sep 17 00:00:00 2001 From: Eli Polonsky Date: Tue, 11 Aug 2020 13:15:18 +0300 Subject: [PATCH 20/43] fix(eks): clusters in a FAILED state are not detected (#9553) Fixes https://github.com/aws/aws-cdk/issues/9529 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/cluster-resource-handler/cluster.ts | 6 ++++- .../test/test.cluster-resource-provider.ts | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts index 48c7baa85ac6a..a0a726b503e5d 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts @@ -196,7 +196,11 @@ export class ClusterResourceHandler extends ResourceHandler { // if cluster is undefined (shouldnt happen) or status is not ACTIVE, we are // not complete. note that the custom resource provider framework forbids // returning attributes (Data) if isComplete is false. - if (cluster?.status !== 'ACTIVE') { + if (cluster?.status === 'FAILED') { + // not very informative, unfortunately the response doesn't contain any error + // information :\ + throw new Error('Cluster is in a FAILED status'); + } else if (cluster?.status !== 'ACTIVE') { return { IsComplete: false, }; diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster-resource-provider.ts b/packages/@aws-cdk/aws-eks/test/test.cluster-resource-provider.ts index e762d6c7abbd3..293bdb90d2844 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster-resource-provider.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster-resource-provider.ts @@ -88,6 +88,30 @@ export = { test.done(); }, + async 'isCreateComplete throws if cluster is FAILED'(test: Test) { + const handler = new ClusterResourceHandler(mocks.client, mocks.newRequest('Create')); + mocks.simulateResponse.describeClusterResponseMockStatus = 'FAILED'; + try { + await handler.isComplete(); + test.ok(false, 'expected error to be thrown'); + } catch (err) { + test.equal(err.message, 'Cluster is in a FAILED status'); + } + test.done(); + }, + + async 'isUpdateComplete throws if cluster is FAILED'(test: Test) { + const handler = new ClusterResourceHandler(mocks.client, mocks.newRequest('Update')); + mocks.simulateResponse.describeClusterResponseMockStatus = 'FAILED'; + try { + await handler.isComplete(); + test.ok(false, 'expected error to be thrown'); + } catch (err) { + test.equal(err.message, 'Cluster is in a FAILED status'); + } + test.done(); + }, + async 'isCreateComplete is complete when cluster is ACTIVE'(test: Test) { const handler = new ClusterResourceHandler(mocks.client, mocks.newRequest('Create')); mocks.simulateResponse.describeClusterResponseMockStatus = 'ACTIVE'; From 979558ef20e852897998dc98297f3d4e7bed6d63 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Tue, 11 Aug 2020 15:37:31 +0100 Subject: [PATCH 21/43] chore: Mergify rule requiring two (or more) approvals on certain PRs (#9599) * chore: Mergify rule requiring two (or more) approvals on certain PRs For security-related or other broadly-impacting PRs, having multiple reviewers can be beneficial. Today, PRs can be manually tagged with 'pr/do-not-merge' and untagged after an artibrary point. An explicit label ('pr/requires-two-approvers`) makes this more explicit and allows for up-front tagging by the PR author. --- .mergify.yml | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/.mergify.yml b/.mergify.yml index bc7c0a843d100..25c67f41b33ea 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -21,7 +21,7 @@ pull_request_rules: conditions: - base!=release - -title~=(WIP|wip) - - -label~=(blocked|do-not-merge|no-squash) + - -label~=(blocked|do-not-merge|no-squash|two-approvers) - -merged - -closed - author!=dependabot[bot] @@ -32,7 +32,32 @@ pull_request_rules: - status-success~=AWS CodeBuild us-east-1 #- status-success=Semantic Pull Request - status-success=mandatory-changes - - name: automatic merge + - name: automatic merge (2+ approvers) + actions: + comment: + message: Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to [allow changes to be pushed to your fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork)). + merge: + strict: smart + method: squash + strict_method: merge + commit_message: title+body + delete_head_branch: {} + conditions: + - base!=release + - -title~=(WIP|wip) + - label~=two-approvers + - -label~=(blocked|do-not-merge|no-squash) + - -merged + - -closed + - author!=dependabot[bot] + - author!=dependabot-preview[bot] + - "#approved-reviews-by>=2" + - -approved-reviews-by~=author + - "#changes-requested-reviews-by=0" + - status-success~=AWS CodeBuild us-east-1 + #- status-success=Semantic Pull Request + - status-success=mandatory-changes + - name: automatic merge (no-squash) actions: comment: message: Thank you for contributing! Your pull request will be updated from master and then merged automatically without squashing (do not update manually, and be sure to [allow changes to be pushed to your fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork)). From 07fedffadf3900d754b5df5a24cc84622299ede4 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Tue, 11 Aug 2020 18:14:29 +0100 Subject: [PATCH 22/43] feat(secretsmanager): Specify secret value at creation (#9594) Enables customers to supply their own secret value in the cases where an auto- generated value is not viable. This exposes the secret value in the cdk output, and CloudFormation template, but not CloudWatch/CloudTrail. fixes #5810 ---- **PR Notes:** 1. Any feedback / thoughts on how else (besides the docstring) to warn folks of the implications of this approach? 2. The secret string can either be a plain string or string representation of a JSON value. I briefly toyed with creating `secretString` and `secretValueJson` or something, and only allowing one or the other, but wasn't sure it was better. Suggestions on this interface welcome. *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-secretsmanager/README.md | 42 ++++++++++++++++--- .../@aws-cdk/aws-secretsmanager/lib/secret.ts | 27 +++++++++++- .../@aws-cdk/aws-secretsmanager/package.json | 1 + .../aws-secretsmanager/test/test.secret.ts | 36 ++++++++++++++++ 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/packages/@aws-cdk/aws-secretsmanager/README.md b/packages/@aws-cdk/aws-secretsmanager/README.md index 540cc9a7fa0be..76efe357b9467 100644 --- a/packages/@aws-cdk/aws-secretsmanager/README.md +++ b/packages/@aws-cdk/aws-secretsmanager/README.md @@ -1,4 +1,5 @@ ## AWS Secrets Manager Construct Library + --- @@ -14,15 +15,35 @@ import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; ``` ### Create a new Secret in a Stack + In order to have SecretsManager generate a new secret value automatically, you can get started with the following: -[example of creating a secret](test/integ.secret.lit.ts) +```ts +// Default secret +const secret = new secretsmanager.Secret(this, 'Secret'); + +// Using the default secret +new iam.User(this, 'User', { + password: secret.secretValue, +}); + +// Templated secret +const templatedSecret = new secretsmanager.Secret(this, 'TemplatedSecret', { + generateSecretString: { + secretStringTemplate: JSON.stringify({ username: 'user' }), + generateStringKey: 'password', + }, +}); + +// Using the templated secret +new iam.User(this, 'OtherUser', { + userName: templatedSecret.secretValueFromJson('username').toString(), + password: templatedSecret.secretValueFromJson('password'), +}); +``` -The `Secret` construct does not allow specifying the `SecretString` property -of the `AWS::SecretsManager::Secret` resource (as this will almost always -lead to the secret being surfaced in plain text and possibly committed to -your source control). +[see also this example of creating a secret](test/integ.secret.lit.ts) If you need to use a pre-existing secret, the recommended way is to manually provision the secret in *AWS SecretsManager* and use the `Secret.fromSecretArn` @@ -43,7 +64,7 @@ A secret can set `RemovalPolicy`. If it set to `RETAIN`, that removing a secret ### Grant permission to use the secret to a role -You must grant permission to a resource for that resource to be allowed to +You must grant permission to a resource for that resource to be allowed to use a secret. This can be achieved with the `Secret.grantRead` and/or `Secret.grantUpdate` method, depending on your need: @@ -55,18 +76,22 @@ secret.grantWrite(role); ``` If, as in the following example, your secret was created with a KMS key: + ```ts const key = new kms.Key(stack, 'KMS'); const secret = new secretsmanager.Secret(stack, 'Secret', { encryptionKey: key }); secret.grantRead(role); secret.grantWrite(role); ``` + then `Secret.grantRead` and `Secret.grantWrite` will also grant the role the relevant encrypt and decrypt permissions to the KMS key through the SecretsManager service principal. ### Rotating a Secret with a custom Lambda function + A rotation schedule can be added to a Secret using a custom Lambda function: + ```ts const fn = new lambda.Function(...); const secret = new secretsmanager.Secret(this, 'Secret'); @@ -76,10 +101,13 @@ secret.addRotationSchedule('RotationSchedule', { automaticallyAfter: Duration.days(15) }); ``` + See [Overview of the Lambda Rotation Function](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets-lambda-function-overview.html) on how to implement a Lambda Rotation Function. ### Rotating database credentials + Define a `SecretRotation` to rotate database credentials: + ```ts new SecretRotation(this, 'SecretRotation', { application: SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, // MySQL single user scheme @@ -90,6 +118,7 @@ new SecretRotation(this, 'SecretRotation', { ``` The secret must be a JSON string with the following format: + ```json { "engine": "", @@ -103,6 +132,7 @@ The secret must be a JSON string with the following format: ``` For the multi user scheme, a `masterSecret` must be specified: + ```ts new SecretRotation(stack, 'SecretRotation', { application: SecretRotationApplication.MYSQL_ROTATION_MULTI_USER, diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index 4ca105f58d59a..e4438ec308b7b 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -103,6 +103,22 @@ export interface SecretProps { */ readonly secretName?: string; + /** + * Secret value (WARNING). + * + * **WARNING:** *It is **highly** encouraged to leave this field undefined and allow SecretsManager to create the secret value. + * The secret string -- if provided -- will be included in the output of the cdk as part of synthesis, + * and will appear in the CloudFormation template in the console*. + * + * Specifies text data that you want to encrypt and store in this new version of the secret. + * May be a simple string value, or a string representation of a JSON structure. + * + * Only one of `secretString` and `generateSecretString` can be provided. + * + * @default - SecretsManager generates a new secret value. + */ + readonly secretString?: string; + /** * Policy to apply when the secret is removed from this stack. * @@ -266,17 +282,26 @@ export class Secret extends SecretBase { throw new Error('`secretStringTemplate` and `generateStringKey` must be specified together.'); } + if (props.generateSecretString && props.secretString) { + throw new Error('Cannot specify both `generateSecretString` and `secretString`.'); + } + const resource = new secretsmanager.CfnSecret(this, 'Resource', { description: props.description, kmsKeyId: props.encryptionKey && props.encryptionKey.keyArn, - generateSecretString: props.generateSecretString || {}, + generateSecretString: props.generateSecretString || (props.secretString ? undefined : {}), name: this.physicalName, + secretString: props.secretString, }); if (props.removalPolicy) { resource.applyRemovalPolicy(props.removalPolicy); } + if (props.secretString) { + this.node.addWarning('Using a `secretString` value which will be visible in plaintext in the CloudFormation template and cdk output.'); + } + this.secretArn = this.getResourceArnAttribute(resource.ref, { service: 'secretsmanager', resource: 'secret', diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index ca00bf77825cb..b80ecfef3fbc3 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -64,6 +64,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts b/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts index 0a295747e7e5f..e1c5bee53dd7e 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts @@ -2,6 +2,7 @@ import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/a import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; +import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as secretsmanager from '../lib'; @@ -574,6 +575,41 @@ export = { test.done(); }, + 'can provide a secret value directly'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret', { + secretString: 'mynotsosecretvalue', + }); + + // THEN + expect(stack).to(haveResource('AWS::SecretsManager::Secret', { + SecretString: 'mynotsosecretvalue', + })); + + test.equals(secret.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.equals(secret.node.metadata[0].data, 'Using a `secretString` value which will be visible in plaintext in the CloudFormation template and cdk output.'); + + test.done(); + }, + + 'throws when specifying secretString and generateStringKey'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + test.throws(() => new secretsmanager.Secret(stack, 'Secret', { + generateSecretString: { + excludeCharacters: '@', + }, + secretString: 'myexistingsecret', + }), /Cannot specify both `generateSecretString` and `secretString`./); + + test.done(); + }, + 'equivalence of SecretValue and Secret.fromSecretAttributes'(test: Test) { // GIVEN const stack = new cdk.Stack(); From 3da0aa99d16e908a39f43f463ac2889dd232c611 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Tue, 11 Aug 2020 20:01:16 +0200 Subject: [PATCH 23/43] feat(core): local bundling provider (#9564) The local bundling provider implements a method `tryBundle()` which should return `true` if local bundling was performed. If `false` is returned, docker bundling will be done. This allows to improve bundling performance when the required dependencies are available locally. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-s3-assets/README.md | 27 +++++++++ packages/@aws-cdk/core/lib/asset-staging.ts | 24 +++++--- packages/@aws-cdk/core/lib/bundling.ts | 38 ++++++++++-- packages/@aws-cdk/core/test/test.staging.ts | 67 ++++++++++++++++++++- 4 files changed, 141 insertions(+), 15 deletions(-) diff --git a/packages/@aws-cdk/aws-s3-assets/README.md b/packages/@aws-cdk/aws-s3-assets/README.md index 3833f750ebe02..86795c8f12598 100644 --- a/packages/@aws-cdk/aws-s3-assets/README.md +++ b/packages/@aws-cdk/aws-s3-assets/README.md @@ -90,6 +90,33 @@ docker program to execute. This may sometime be needed when building in environments where the standard docker cannot be executed (see https://github.com/aws/aws-cdk/issues/8460 for details). +Use `local` to specify a local bundling provider. The provider implements a +method `tryBundle()` which should return `true` if local bundling was performed. +If `false` is returned, docker bundling will be done: + +```ts +new assets.Asset(this, 'BundledAsset', { + path: '/path/to/asset', + bundling: { + local: { + tryBundler(outputDir: string, options: BundlingOptions) { + if (canRunLocally) { + // perform local bundling here + return true; + } + return false; + }, + }, + // Docker bundling fallback + image: BundlingDockerImage.fromRegistry('alpine'), + command: ['bundle'], + }, +}); +``` + +Although optional, it's recommended to provide a local bundling method which can +greatly improve performance. + ## CloudFormation Resource Metadata > NOTE: This section is relevant for authors of AWS Resource Constructs. diff --git a/packages/@aws-cdk/core/lib/asset-staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts index 0d1c9ecad7c39..8a3ae1452b464 100644 --- a/packages/@aws-cdk/core/lib/asset-staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -178,21 +178,27 @@ export class AssetStaging extends Construct { ...options.volumes ?? [], ]; + let localBundling: boolean | undefined; try { process.stderr.write(`Bundling asset ${this.construct.path}...\n`); - options.image._run({ - command: options.command, - user, - volumes, - environment: options.environment, - workingDirectory: options.workingDirectory ?? AssetStaging.BUNDLING_INPUT_DIR, - }); + + localBundling = options.local?.tryBundle(bundleDir, options); + if (!localBundling) { + options.image._run({ + command: options.command, + user, + volumes, + environment: options.environment, + workingDirectory: options.workingDirectory ?? AssetStaging.BUNDLING_INPUT_DIR, + }); + } } catch (err) { - throw new Error(`Failed to run bundling Docker image for asset ${this.construct.path}: ${err}`); + throw new Error(`Failed to bundle asset ${this.construct.path}: ${err}`); } if (FileSystem.isEmpty(bundleDir)) { - throw new Error(`Bundling did not produce any output. Check that your container writes content to ${AssetStaging.BUNDLING_OUTPUT_DIR}.`); + const outputDir = localBundling ? bundleDir : AssetStaging.BUNDLING_OUTPUT_DIR; + throw new Error(`Bundling did not produce any output. Check that content is written to ${outputDir}.`); } return bundleDir; diff --git a/packages/@aws-cdk/core/lib/bundling.ts b/packages/@aws-cdk/core/lib/bundling.ts index 6a90d5dbb742a..392b4bd77c519 100644 --- a/packages/@aws-cdk/core/lib/bundling.ts +++ b/packages/@aws-cdk/core/lib/bundling.ts @@ -12,7 +12,7 @@ export interface BundlingOptions { readonly image: BundlingDockerImage; /** - * The command to run in the container. + * The command to run in the Docker container. * * @example ['npm', 'install'] * @@ -30,21 +30,21 @@ export interface BundlingOptions { readonly volumes?: DockerVolume[]; /** - * The environment variables to pass to the container. + * The environment variables to pass to the Docker container. * * @default - no environment variables. */ readonly environment?: { [key: string]: string; }; /** - * Working directory inside the container. + * Working directory inside the Docker container. * * @default /asset-input */ readonly workingDirectory?: string; /** - * The user to use when running the container. + * The user to use when running the Docker container. * * user | user:group | uid | uid:gid | user:gid | uid:group * @@ -53,6 +53,36 @@ export interface BundlingOptions { * @default - uid:gid of the current user or 1000:1000 on Windows */ readonly user?: string; + + /** + * Local bundling provider. + * + * The provider implements a method `tryBundle()` which should return `true` + * if local bundling was performed. If `false` is returned, docker bundling + * will be done. + * + * @default - bundling will only be performed in a Docker container + * + * @experimental + */ + readonly local?: ILocalBundling; +} + +/** + * Local bundling + * + * @experimental + */ +export interface ILocalBundling { + /** + * This method is called before attempting docker bundling to allow the + * bundler to be executed locally. If the local bundler exists, and bundling + * was performed locally, return `true`. Otherwise, return `false`. + * + * @param outputDir the directory where the bundled asset should be output + * @param options bundling options for this asset + */ + tryBundle(outputDir: string, options: BundlingOptions): boolean; } /** diff --git a/packages/@aws-cdk/core/test/test.staging.ts b/packages/@aws-cdk/core/test/test.staging.ts index 7bd11df1f103b..434422fc949c8 100644 --- a/packages/@aws-cdk/core/test/test.staging.ts +++ b/packages/@aws-cdk/core/test/test.staging.ts @@ -4,7 +4,7 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as fs from 'fs-extra'; import { Test } from 'nodeunit'; import * as sinon from 'sinon'; -import { App, AssetHashType, AssetStaging, BundlingDockerImage, Stack } from '../lib'; +import { App, AssetHashType, AssetStaging, BundlingDockerImage, BundlingOptions, Stack } from '../lib'; const STUB_INPUT_FILE = '/tmp/docker-stub.input'; @@ -281,7 +281,7 @@ export = { image: BundlingDockerImage.fromRegistry('this-is-an-invalid-docker-image'), command: [ DockerStubCommand.FAIL ], }, - }), /Failed to run bundling Docker image for asset stack\/Asset/); + }), /Failed to bundle asset stack\/Asset/); test.equal( readDockerStubInput(), `run --rm ${USER_ARG} -v /input:/asset-input:delegated -v /output:/asset-output:delegated -w /asset-input this-is-an-invalid-docker-image DOCKER_STUB_FAIL`, @@ -289,6 +289,69 @@ export = { test.done(); }, + + 'with local bundling'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'stack'); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1'); + + // WHEN + let dir: string | undefined; + let opts: BundlingOptions | undefined; + new AssetStaging(stack, 'Asset', { + sourcePath: directory, + bundling: { + image: BundlingDockerImage.fromRegistry('alpine'), + command: [DockerStubCommand.SUCCESS], + local: { + tryBundle(outputDir: string, options: BundlingOptions): boolean { + dir = outputDir; + opts = options; + fs.writeFileSync(path.join(outputDir, 'hello.txt'), 'hello'); // output cannot be empty + return true; + }, + }, + }, + }); + + // THEN + test.ok(dir && /asset-bundle-/.test(dir)); + test.equals(opts?.command?.[0], DockerStubCommand.SUCCESS); + test.throws(() => readDockerStubInput()); + + if (dir) { + fs.removeSync(path.join(dir, 'hello.txt')); + } + + test.done(); + }, + + 'with local bundling returning false'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'stack'); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1'); + + // WHEN + new AssetStaging(stack, 'Asset', { + sourcePath: directory, + bundling: { + image: BundlingDockerImage.fromRegistry('alpine'), + command: [DockerStubCommand.SUCCESS], + local: { + tryBundle(_bundleDir: string): boolean { + return false; + }, + }, + }, + }); + + // THEN + test.ok(readDockerStubInput()); + + test.done(); + }, }; function readDockerStubInput() { From 044e7d32378e27493664423da09384dfc512ecc1 Mon Sep 17 00:00:00 2001 From: Hyeonsoo David Lee Date: Wed, 12 Aug 2020 03:23:37 +0900 Subject: [PATCH 24/43] chore(ecs): fix comment @default on CloudMapOptions.dnsRecordType (#9412) https://github.com/aws/aws-cdk/blob/b688913b7534867c4cb584e491bf6e89437b48d9/packages/%40aws-cdk/aws-ecs/lib/base/base-service.ts#L517-L531 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ecs/lib/base/base-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index de24422c27159..eadff8f528b8a 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -742,7 +742,7 @@ export interface CloudMapOptions { /** * The DNS record type that you want AWS Cloud Map to create. The supported record types are A or SRV. * - * @default DnsRecordType.A + * @default - DnsRecordType.A if TaskDefinition.networkMode = AWS_VPC, otherwise DnsRecordType.SRV */ readonly dnsRecordType?: cloudmap.DnsRecordType.A | cloudmap.DnsRecordType.SRV, From 9fa4cd02050d9a98466884c25fe8377778ef3d95 Mon Sep 17 00:00:00 2001 From: Inseo Kim Date: Wed, 12 Aug 2020 03:52:07 +0900 Subject: [PATCH 25/43] chore: replace single quote with backtick (#9591) Modify so that `timer.display()` is printed correctly. ## Before ```shell aws-cdk: Build failed. ${timers.display()} aws-cdk: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! aws-cdk: error Command failed with exit code 1. ``` ## After ```shell aws-cdk: Build failed. Total time (47.4s) | /app/node_modules/typescript/bin/tsc (1.5s) | ./generate.sh (0.1s) aws-cdk: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! aws-cdk: error Command failed with exit code 1. ``` ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- tools/cdk-build-tools/bin/cdk-build.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cdk-build-tools/bin/cdk-build.ts b/tools/cdk-build-tools/bin/cdk-build.ts index b69ecc4a3c5ca..87f269364adb8 100644 --- a/tools/cdk-build-tools/bin/cdk-build.ts +++ b/tools/cdk-build-tools/bin/cdk-build.ts @@ -58,7 +58,7 @@ main().then(() => { }).catch(e => { buildTimer.end(); process.stderr.write(`${e.toString()}\n`); - process.stderr.write('Build failed. ${timers.display()}\n'); + process.stderr.write(`Build failed. ${timers.display()}\n`); process.stderr.write('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n'); process.exit(1); }); From b75ce4e5a3685be9d880dbc66c66ace466e45730 Mon Sep 17 00:00:00 2001 From: Somaya Date: Tue, 11 Aug 2020 12:11:39 -0700 Subject: [PATCH 26/43] update eks assignee in github action workflow (#9571) --- .github/workflows/issue-label-assign.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index 8233cd7837cb8..ba60295cd406b 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -72,7 +72,7 @@ jobs: {"keywords":["[@aws-cdk/aws-ecr]","[aws-ecr]","[ecr]"],"labels":["@aws-cdk/aws-ecr"],"assignees":["MrArnoldPalmer"]}, {"keywords":["[@aws-cdk/aws-ecr-assets]","[aws-ecr-assets]","[ecr-assets]","[ecr assets]","[ecrassets]"],"labels":["@aws-cdk/aws-ecr-assets"],"assignees":["eladb"]}, {"keywords":["[@aws-cdk/aws-efs]","[aws-efs]","[efs]"],"labels":["@aws-cdk/aws-efs"],"assignees":["rix0rrr"]}, - {"keywords":["[@aws-cdk/aws-eks]","[aws-eks]","[eks]"],"labels":["@aws-cdk/aws-eks"],"assignees":["eladb"]}, + {"keywords":["[@aws-cdk/aws-eks]","[aws-eks]","[eks]"],"labels":["@aws-cdk/aws-eks"],"assignees":["iliapolo"]}, {"keywords":["[@aws-cdk/aws-elasticache]","[aws-elasticache]","[elasticache]","[elastic cache]","[elastic-cache]"],"labels":["@aws-cdk/aws-elasticache"],"assignees":["iliapolo"]}, {"keywords":["[@aws-cdk/aws-elasticbeanstalk]","[aws-elasticbeanstalk]","[elasticbeanstalk]","[elastic beanstalk]","[elastic-beanstalk]"],"labels":["@aws-cdk/aws-elasticbeanstalk"],"assignees":["skinny85"]}, {"keywords":["[@aws-cdk/aws-elasticloadbalancing]","[aws-elasticloadbalancing]","[elasticloadbalancing]","[elastic loadbalancing]","[elastic-loadbalancing]","[elb]"],"labels":["@aws-cdk/aws-elasticloadbalancing"],"assignees":["rix0rrr"]}, From 908dd69ec6e7d2037e299513e424d88921ebe04f Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 11 Aug 2020 21:33:27 +0200 Subject: [PATCH 27/43] docs(codepipeline): document required GitHub token scopes (#9595) Our documentation here was severely lacking making it hard to set up correctly. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-codepipeline-actions/README.md | 8 ++++---- .../lib/github/source-action.ts | 10 ++++++++++ packages/@aws-cdk/pipelines/README.md | 1 - 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/aws-codepipeline-actions/README.md b/packages/@aws-cdk/aws-codepipeline-actions/README.md index 7edd0244bcbcb..3a4497529b38d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/README.md +++ b/packages/@aws-cdk/aws-codepipeline-actions/README.md @@ -66,7 +66,8 @@ new codepipeline_actions.CodeBuildAction({ If you want to use a GitHub repository as the source, you must create: -* A [GitHub Access Token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) +* A [GitHub Access Token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line), + with scopes **repo** and **admin:repo_hook**. * A [Secrets Manager PlainText Secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) with the value of the **GitHub Access Token**. Pick whatever name you want (for example `my-github-token`) and pass it as the argument of `oauthToken`. @@ -83,7 +84,6 @@ const sourceAction = new codepipeline_actions.GitHubSourceAction({ oauthToken: cdk.SecretValue.secretsManager('my-github-token'), output: sourceOutput, branch: 'develop', // default: 'master' - trigger: codepipeline_actions.GitHubTrigger.POLL // default: 'WEBHOOK', 'NONE' is also possible for no Source trigger }); pipeline.addStage({ stageName: 'Source', @@ -694,7 +694,7 @@ new codepipeline_actions.AlexaSkillDeployAction({ }); ``` -### AWS Service Catalog +### AWS Service Catalog You can deploy a CloudFormation template to an existing Service Catalog product with the following action: @@ -713,7 +713,7 @@ new codepipeline.Pipeline(this, 'Pipeline', { productId: "prod-XXXXXXXX", }), }, - ], + ], }); ``` diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/github/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/github/source-action.ts index 4283b7617f010..75d14cf0fbbe9 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/github/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/github/source-action.ts @@ -65,6 +65,13 @@ export interface GitHubSourceActionProps extends codepipeline.CommonActionProps * * const oauth = cdk.SecretValue.secretsManager('my-github-token'); * new GitHubSource(this, 'GitHubAction', { oauthToken: oauth, ... }); + * + * The GitHub Personal Access Token should have these scopes: + * + * * **repo** - to read the repository + * * **admin:repo_hook** - if you plan to use webhooks (true by default) + * + * @see https://docs.aws.amazon.com/codepipeline/latest/userguide/GitHub-create-personal-token-CLI.html */ readonly oauthToken: SecretValue; @@ -75,6 +82,9 @@ export interface GitHubSourceActionProps extends codepipeline.CommonActionProps * With "POLL", CodePipeline periodically checks the source for changes * With "None", the action is not triggered through changes in the source * + * To use `WEBHOOK`, your GitHub Personal Access Token should have + * **admin:repo_hook** scope (in addition to the regular **repo** scope). + * * @default GitHubTrigger.WEBHOOK */ readonly trigger?: GitHubTrigger; diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index ff92b365d56e0..431016a0d39c3 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -126,7 +126,6 @@ class MyPipelineStack extends Stack { actionName: 'GitHub', output: sourceArtifact, oauthToken: SecretValue.secretsManager('GITHUB_TOKEN_NAME'), - trigger: codepipeline_actions.GitHubTrigger.POLL, // Replace these with your actual GitHub project name owner: 'OWNER', repo: 'REPO', From ea39fbda26ce649e9093100fab12822ea078d6ab Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Tue, 11 Aug 2020 21:47:01 +0100 Subject: [PATCH 28/43] revert(secretsmanager): Specify secret value at creation (#9610) This reverts commit 07fedffadf3900d754b5df5a24cc84622299ede4. Further team discussion deemed this feature too dangerous to support within the CDK. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-secretsmanager/README.md | 42 +++---------------- .../@aws-cdk/aws-secretsmanager/lib/secret.ts | 27 +----------- .../@aws-cdk/aws-secretsmanager/package.json | 1 - .../aws-secretsmanager/test/test.secret.ts | 36 ---------------- 4 files changed, 7 insertions(+), 99 deletions(-) diff --git a/packages/@aws-cdk/aws-secretsmanager/README.md b/packages/@aws-cdk/aws-secretsmanager/README.md index 76efe357b9467..540cc9a7fa0be 100644 --- a/packages/@aws-cdk/aws-secretsmanager/README.md +++ b/packages/@aws-cdk/aws-secretsmanager/README.md @@ -1,5 +1,4 @@ ## AWS Secrets Manager Construct Library - --- @@ -15,35 +14,15 @@ import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; ``` ### Create a new Secret in a Stack - In order to have SecretsManager generate a new secret value automatically, you can get started with the following: -```ts -// Default secret -const secret = new secretsmanager.Secret(this, 'Secret'); - -// Using the default secret -new iam.User(this, 'User', { - password: secret.secretValue, -}); - -// Templated secret -const templatedSecret = new secretsmanager.Secret(this, 'TemplatedSecret', { - generateSecretString: { - secretStringTemplate: JSON.stringify({ username: 'user' }), - generateStringKey: 'password', - }, -}); - -// Using the templated secret -new iam.User(this, 'OtherUser', { - userName: templatedSecret.secretValueFromJson('username').toString(), - password: templatedSecret.secretValueFromJson('password'), -}); -``` +[example of creating a secret](test/integ.secret.lit.ts) -[see also this example of creating a secret](test/integ.secret.lit.ts) +The `Secret` construct does not allow specifying the `SecretString` property +of the `AWS::SecretsManager::Secret` resource (as this will almost always +lead to the secret being surfaced in plain text and possibly committed to +your source control). If you need to use a pre-existing secret, the recommended way is to manually provision the secret in *AWS SecretsManager* and use the `Secret.fromSecretArn` @@ -64,7 +43,7 @@ A secret can set `RemovalPolicy`. If it set to `RETAIN`, that removing a secret ### Grant permission to use the secret to a role -You must grant permission to a resource for that resource to be allowed to +You must grant permission to a resource for that resource to be allowed to use a secret. This can be achieved with the `Secret.grantRead` and/or `Secret.grantUpdate` method, depending on your need: @@ -76,22 +55,18 @@ secret.grantWrite(role); ``` If, as in the following example, your secret was created with a KMS key: - ```ts const key = new kms.Key(stack, 'KMS'); const secret = new secretsmanager.Secret(stack, 'Secret', { encryptionKey: key }); secret.grantRead(role); secret.grantWrite(role); ``` - then `Secret.grantRead` and `Secret.grantWrite` will also grant the role the relevant encrypt and decrypt permissions to the KMS key through the SecretsManager service principal. ### Rotating a Secret with a custom Lambda function - A rotation schedule can be added to a Secret using a custom Lambda function: - ```ts const fn = new lambda.Function(...); const secret = new secretsmanager.Secret(this, 'Secret'); @@ -101,13 +76,10 @@ secret.addRotationSchedule('RotationSchedule', { automaticallyAfter: Duration.days(15) }); ``` - See [Overview of the Lambda Rotation Function](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets-lambda-function-overview.html) on how to implement a Lambda Rotation Function. ### Rotating database credentials - Define a `SecretRotation` to rotate database credentials: - ```ts new SecretRotation(this, 'SecretRotation', { application: SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, // MySQL single user scheme @@ -118,7 +90,6 @@ new SecretRotation(this, 'SecretRotation', { ``` The secret must be a JSON string with the following format: - ```json { "engine": "", @@ -132,7 +103,6 @@ The secret must be a JSON string with the following format: ``` For the multi user scheme, a `masterSecret` must be specified: - ```ts new SecretRotation(stack, 'SecretRotation', { application: SecretRotationApplication.MYSQL_ROTATION_MULTI_USER, diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index e4438ec308b7b..4ca105f58d59a 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -103,22 +103,6 @@ export interface SecretProps { */ readonly secretName?: string; - /** - * Secret value (WARNING). - * - * **WARNING:** *It is **highly** encouraged to leave this field undefined and allow SecretsManager to create the secret value. - * The secret string -- if provided -- will be included in the output of the cdk as part of synthesis, - * and will appear in the CloudFormation template in the console*. - * - * Specifies text data that you want to encrypt and store in this new version of the secret. - * May be a simple string value, or a string representation of a JSON structure. - * - * Only one of `secretString` and `generateSecretString` can be provided. - * - * @default - SecretsManager generates a new secret value. - */ - readonly secretString?: string; - /** * Policy to apply when the secret is removed from this stack. * @@ -282,26 +266,17 @@ export class Secret extends SecretBase { throw new Error('`secretStringTemplate` and `generateStringKey` must be specified together.'); } - if (props.generateSecretString && props.secretString) { - throw new Error('Cannot specify both `generateSecretString` and `secretString`.'); - } - const resource = new secretsmanager.CfnSecret(this, 'Resource', { description: props.description, kmsKeyId: props.encryptionKey && props.encryptionKey.keyArn, - generateSecretString: props.generateSecretString || (props.secretString ? undefined : {}), + generateSecretString: props.generateSecretString || {}, name: this.physicalName, - secretString: props.secretString, }); if (props.removalPolicy) { resource.applyRemovalPolicy(props.removalPolicy); } - if (props.secretString) { - this.node.addWarning('Using a `secretString` value which will be visible in plaintext in the CloudFormation template and cdk output.'); - } - this.secretArn = this.getResourceArnAttribute(resource.ref, { service: 'secretsmanager', resource: 'secret', diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index b80ecfef3fbc3..ca00bf77825cb 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -64,7 +64,6 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts b/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts index e1c5bee53dd7e..0a295747e7e5f 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts @@ -2,7 +2,6 @@ import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/a import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; -import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as secretsmanager from '../lib'; @@ -575,41 +574,6 @@ export = { test.done(); }, - 'can provide a secret value directly'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = new secretsmanager.Secret(stack, 'Secret', { - secretString: 'mynotsosecretvalue', - }); - - // THEN - expect(stack).to(haveResource('AWS::SecretsManager::Secret', { - SecretString: 'mynotsosecretvalue', - })); - - test.equals(secret.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.equals(secret.node.metadata[0].data, 'Using a `secretString` value which will be visible in plaintext in the CloudFormation template and cdk output.'); - - test.done(); - }, - - 'throws when specifying secretString and generateStringKey'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // THEN - test.throws(() => new secretsmanager.Secret(stack, 'Secret', { - generateSecretString: { - excludeCharacters: '@', - }, - secretString: 'myexistingsecret', - }), /Cannot specify both `generateSecretString` and `secretString`./); - - test.done(); - }, - 'equivalence of SecretValue and Secret.fromSecretAttributes'(test: Test) { // GIVEN const stack = new cdk.Stack(); From d9d9b908ca149b189f0e1bde7df0d75afd5b26ff Mon Sep 17 00:00:00 2001 From: kaizen3031593 <36202692+kaizen3031593@users.noreply.github.com> Date: Tue, 11 Aug 2020 17:01:55 -0400 Subject: [PATCH 29/43] feat(lambda): autoscaling for lambda aliases (#8883) --- packages/@aws-cdk/aws-lambda/README.md | 29 +++ packages/@aws-cdk/aws-lambda/lib/alias.ts | 36 +++ packages/@aws-cdk/aws-lambda/lib/index.ts | 1 + .../private/scalable-function-attribute.ts | 41 ++++ .../aws-lambda/lib/scalable-attribute-api.ts | 46 ++++ packages/@aws-cdk/aws-lambda/package.json | 2 + .../test/integ.autoscaling.lit.expected.json | 164 ++++++++++++++ .../aws-lambda/test/integ.autoscaling.lit.ts | 53 +++++ .../@aws-cdk/aws-lambda/test/test.alias.ts | 214 +++++++++++++++++- 9 files changed, 584 insertions(+), 2 deletions(-) create mode 100644 packages/@aws-cdk/aws-lambda/lib/private/scalable-function-attribute.ts create mode 100644 packages/@aws-cdk/aws-lambda/lib/scalable-attribute-api.ts create mode 100644 packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.expected.json create mode 100644 packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.ts diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index 07cb929bae067..9c27790061093 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -272,6 +272,35 @@ const fn = new lambda.Function(this, 'MyFunction', { See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html) managing concurrency. +### AutoScaling + +You can use Application AutoScaling to automatically configure the provisioned concurrency for your functions. AutoScaling can be set to track utilization or be based on a schedule. To configure AutoScaling on a function alias: + +```ts +const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version, +}); + +// Create AutoScaling target +const as = alias.addAutoScaling({ maxCapacity: 50 }) + +// Configure Target Tracking +as.scaleOnUtilization({ + utilizationTarget: 0.5, +}); + +// Configure Scheduled Scaling +as.scaleOnSchedule('ScaleUpInTheMorning', { + schedule: appscaling.Schedule.cron({ hour: '8', minute: '0'}), + minCapacity: 20, +}); +``` + +[Example of Lambda AutoScaling usage](test/integ.autoscaling.lit.ts) + +See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/invocation-scaling.html) on autoscaling lambda functions. + ### Log Group Lambda functions automatically create a log group with the name `/aws/lambda/` upon first execution with diff --git a/packages/@aws-cdk/aws-lambda/lib/alias.ts b/packages/@aws-cdk/aws-lambda/lib/alias.ts index 638f52e11a09f..c740b6620a061 100644 --- a/packages/@aws-cdk/aws-lambda/lib/alias.ts +++ b/packages/@aws-cdk/aws-lambda/lib/alias.ts @@ -1,9 +1,13 @@ +import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import * as iam from '@aws-cdk/aws-iam'; import { Construct } from '@aws-cdk/core'; import { EventInvokeConfigOptions } from './event-invoke-config'; import { IFunction, QualifiedFunctionBase } from './function-base'; import { extractQualifierFromArn, IVersion } from './lambda-version'; import { CfnAlias } from './lambda.generated'; +import { ScalableFunctionAttribute } from './private/scalable-function-attribute'; +import { AutoScalingOptions, IScalableFunctionAttribute } from './scalable-attribute-api'; export interface IAlias extends IFunction { /** @@ -129,6 +133,9 @@ export class Alias extends QualifiedFunctionBase implements IAlias { protected readonly canCreatePermissions: boolean = true; + private scalableAlias?: ScalableFunctionAttribute; + private readonly scalingRole: iam.IRole; + constructor(scope: Construct, id: string, props: AliasProps) { super(scope, id, { physicalName: props.aliasName, @@ -147,6 +154,15 @@ export class Alias extends QualifiedFunctionBase implements IAlias { provisionedConcurrencyConfig: this.determineProvisionedConcurrency(props), }); + // Use a Service Linked Role + // https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html + this.scalingRole = iam.Role.fromRoleArn(this, 'ScalingRole', this.stack.formatArn({ + service: 'iam', + region: '', + resource: 'role/aws-service-role/lambda.application-autoscaling.amazonaws.com', + resourceName: 'AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency', + })); + this.functionArn = this.getResourceArnAttribute(alias.ref, { service: 'lambda', resource: 'function', @@ -193,6 +209,26 @@ export class Alias extends QualifiedFunctionBase implements IAlias { }); } + /** + * Configure provisioned concurrency autoscaling on a function alias. Returns a scalable attribute that can call + * `scaleOnUtilization()` and `scaleOnSchedule()`. + * + * @param options Autoscaling options + */ + public addAutoScaling(options: AutoScalingOptions): IScalableFunctionAttribute { + if (this.scalableAlias) { + throw new Error('AutoScaling already enabled for this alias'); + } + return this.scalableAlias = new ScalableFunctionAttribute(this, 'AliasScaling', { + minCapacity: options.minCapacity ?? 1, + maxCapacity: options.maxCapacity, + resourceId: `function:${this.functionName}`, + dimension: 'lambda:function:ProvisionedConcurrency', + serviceNamespace: appscaling.ServiceNamespace.LAMBDA, + role: this.scalingRole, + }); + } + /** * Calculate the routingConfig parameter from the input props */ diff --git a/packages/@aws-cdk/aws-lambda/lib/index.ts b/packages/@aws-cdk/aws-lambda/lib/index.ts index b1d676e234a9b..3581a40cdf535 100644 --- a/packages/@aws-cdk/aws-lambda/lib/index.ts +++ b/packages/@aws-cdk/aws-lambda/lib/index.ts @@ -13,6 +13,7 @@ export * from './event-source'; export * from './event-source-mapping'; export * from './destination'; export * from './event-invoke-config'; +export * from './scalable-attribute-api'; export * from './log-retention'; diff --git a/packages/@aws-cdk/aws-lambda/lib/private/scalable-function-attribute.ts b/packages/@aws-cdk/aws-lambda/lib/private/scalable-function-attribute.ts new file mode 100644 index 0000000000000..21b09cd2c79e2 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/lib/private/scalable-function-attribute.ts @@ -0,0 +1,41 @@ +import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; +import { Construct, Token } from '@aws-cdk/core'; +import { IScalableFunctionAttribute, UtilizationScalingOptions } from '../scalable-attribute-api'; + +/** + * A scalable lambda alias attribute + */ +export class ScalableFunctionAttribute extends appscaling.BaseScalableAttribute implements IScalableFunctionAttribute{ + constructor(scope: Construct, id: string, props: ScalableFunctionAttributeProps){ + super(scope, id, props); + } + + /** + * Scale out or in to keep utilization at a given level. The utilization is tracked by the + * LambdaProvisionedConcurrencyUtilization metric, emitted by lambda. See: + * https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html#monitoring-metrics-concurrency + */ + public scaleOnUtilization(options: UtilizationScalingOptions) { + if ( !Token.isUnresolved(options.utilizationTarget) && (options.utilizationTarget < 0.1 || options.utilizationTarget > 0.9)) { + throw new Error(`Utilization Target should be between 0.1 and 0.9. Found ${options.utilizationTarget}.`); + } + super.doScaleToTrackMetric('Tracking', { + targetValue: options.utilizationTarget, + predefinedMetric: appscaling.PredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION, + ...options, + }); + } + + /** + * Scale out or in based on schedule. + */ + public scaleOnSchedule(id: string, action: appscaling.ScalingSchedule) { + super.doScaleOnSchedule(id, action); + } +} + +/** + * Properties of a scalable function attribute + */ +export interface ScalableFunctionAttributeProps extends appscaling.BaseScalableAttributeProps { +} diff --git a/packages/@aws-cdk/aws-lambda/lib/scalable-attribute-api.ts b/packages/@aws-cdk/aws-lambda/lib/scalable-attribute-api.ts new file mode 100644 index 0000000000000..e64fcbd5a8ca7 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/lib/scalable-attribute-api.ts @@ -0,0 +1,46 @@ +import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; +import { IConstruct } from '@aws-cdk/core'; + + +/** + * Interface for scalable attributes + */ +export interface IScalableFunctionAttribute extends IConstruct { + /** + * Scale out or in to keep utilization at a given level. The utilization is tracked by the + * LambdaProvisionedConcurrencyUtilization metric, emitted by lambda. See: + * https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html#monitoring-metrics-concurrency + */ + scaleOnUtilization(options: UtilizationScalingOptions): void; + /** + * Scale out or in based on schedule. + */ + scaleOnSchedule(id: string, actions: appscaling.ScalingSchedule): void; +} + +/** + * Options for enabling Lambda utilization tracking + */ +export interface UtilizationScalingOptions extends appscaling.BaseTargetTrackingProps { + /** + * Utilization target for the attribute. For example, .5 indicates that 50 percent of allocated provisioned concurrency is in use. + */ + readonly utilizationTarget: number; +} + +/** + * Properties for enabling Lambda autoscaling + */ +export interface AutoScalingOptions { + /** + * Minimum capacity to scale to + * + * @default 1 + */ + readonly minCapacity?: number; + + /** + * Maximum capacity to scale to + */ + readonly maxCapacity: number; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index d62071663eb02..a4274700c3e5a 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -83,6 +83,7 @@ "sinon": "^9.0.2" }, "dependencies": { + "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-codeguruprofiler": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -99,6 +100,7 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-applicationautoscaling": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-codeguruprofiler": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.expected.json b/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.expected.json new file mode 100644 index 0000000000000..39ff5f8f0e0fb --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.expected.json @@ -0,0 +1,164 @@ +{ + "Resources": { + "MyLambdaServiceRole4539ECB6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "MyLambdaCCE802FB": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = async () => {\nconsole.log('hello world');\n};" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyLambdaServiceRole4539ECB6", + "Arn" + ] + }, + "Runtime": "nodejs10.x" + }, + "DependsOn": [ + "MyLambdaServiceRole4539ECB6" + ] + }, + "MyLambdaVersion16CDE3C40": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "MyLambdaCCE802FB" + }, + "Description": "integ-test" + } + }, + "Alias325C5727": { + "Type": "AWS::Lambda::Alias", + "Properties": { + "FunctionName": { + "Ref": "MyLambdaCCE802FB" + }, + "FunctionVersion": { + "Fn::GetAtt": [ + "MyLambdaVersion16CDE3C40", + "Version" + ] + }, + "Name": "prod" + } + }, + "AliasAliasScalingTarget7449FF0E": { + "Type": "AWS::ApplicationAutoScaling::ScalableTarget", + "Properties": { + "MaxCapacity": 50, + "MinCapacity": 3, + "ResourceId": { + "Fn::Join": [ + "", + [ + "function:", + { + "Fn::Select": [ + 6, + { + "Fn::Split": [ + ":", + { + "Ref": "Alias325C5727" + } + ] + } + ] + }, + ":prod" + ] + ] + }, + "RoleARN": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/aws-service-role/lambda.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency" + ] + ] + }, + "ScalableDimension": "lambda:function:ProvisionedConcurrency", + "ServiceNamespace": "lambda", + "ScheduledActions": [ + { + "ScalableTargetAction": { + "MinCapacity": 20 + }, + "Schedule": "cron(0 8 * * ? *)", + "ScheduledActionName": "ScaleUpInTheMorning" + }, + { + "ScalableTargetAction": { + "MaxCapacity": 20 + }, + "Schedule": "cron(0 20 * * ? *)", + "ScheduledActionName": "ScaleDownAtNight" + } + ] + } + }, + "AliasAliasScalingTargetTrackingA7718D48": { + "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", + "Properties": { + "PolicyName": "awslambdaautoscalingAliasAliasScalingTargetTrackingD339330D", + "PolicyType": "TargetTrackingScaling", + "ScalingTargetId": { + "Ref": "AliasAliasScalingTarget7449FF0E" + }, + "TargetTrackingScalingPolicyConfiguration": { + "PredefinedMetricSpecification": { + "PredefinedMetricType": "LambdaProvisionedConcurrencyUtilization" + }, + "TargetValue": 0.5 + } + } + } + }, + "Outputs": { + "FunctionName": { + "Value": { + "Ref": "MyLambdaCCE802FB" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.ts b/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.ts new file mode 100644 index 0000000000000..360dda2a1b772 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/integ.autoscaling.lit.ts @@ -0,0 +1,53 @@ +import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; +import * as cdk from '@aws-cdk/core'; +import * as lambda from '../lib'; + +/** +* Stack verification steps: +* aws application-autoscaling describe-scalable-targets --service-namespace lambda --resource-ids function::prod +* has a minCapacity of 3 and maxCapacity of 50 +*/ +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const fn = new lambda.Function(this, 'MyLambda', { + code: new lambda.InlineCode('exports.handler = async () => {\nconsole.log(\'hello world\');\n};'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const version = fn.addVersion('1', undefined, 'integ-test'); + + const alias = new lambda.Alias(this, 'Alias', { + aliasName: 'prod', + version, + }); + + const scalingTarget = alias.addAutoScaling({ minCapacity: 3, maxCapacity: 50 }); + + scalingTarget.scaleOnUtilization({ + utilizationTarget: 0.5, + }); + + scalingTarget.scaleOnSchedule('ScaleUpInTheMorning', { + schedule: appscaling.Schedule.cron({ hour: '8', minute: '0'}), + minCapacity: 20, + }); + + scalingTarget.scaleOnSchedule('ScaleDownAtNight', { + schedule: appscaling.Schedule.cron({ hour: '20', minute: '0'}), + maxCapacity: 20, + }); + + new cdk.CfnOutput(this, 'FunctionName', { + value: fn.functionName, + }); + } +} + +const app = new cdk.App(); + +new TestStack(app, 'aws-lambda-autoscaling'); + +app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/test.alias.ts b/packages/@aws-cdk/aws-lambda/test/test.alias.ts index abbb8c1716b0f..af24cca911a5c 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.alias.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.alias.ts @@ -1,6 +1,7 @@ -import { beASupersetOfTemplate, expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { arrayWith, beASupersetOfTemplate, expect, haveResource, haveResourceLike, objectLike } from '@aws-cdk/assert'; +import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; -import { Stack } from '@aws-cdk/core'; +import { Lazy, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as lambda from '../lib'; @@ -430,4 +431,213 @@ export = { test.done(); }, + + 'can enable AutoScaling on aliases'(test: Test): void { + // GIVEN + const stack = new Stack(); + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const version = fn.addVersion('1', undefined, 'testing'); + + const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version, + }); + + // WHEN + alias.addAutoScaling({ maxCapacity: 5}); + + // THEN + expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + MinCapacity: 1, + MaxCapacity: 5, + ResourceId: objectLike({ + 'Fn::Join': arrayWith(arrayWith( + 'function:', + objectLike({ + 'Fn::Select': arrayWith( + {'Fn::Split': arrayWith( + {Ref: 'Alias325C5727' }), + }, + ), + }), + ':prod', + )), + }), + })); + + test.done(); + }, + + 'can enable AutoScaling on aliases with Provisioned Concurrency set'(test: Test): void { + // GIVEN + const stack = new Stack(); + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const version = fn.addVersion('1', undefined, 'testing'); + + const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version, + provisionedConcurrentExecutions: 10, + }); + + // WHEN + alias.addAutoScaling({ maxCapacity: 5}); + + // THEN + expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + MinCapacity: 1, + MaxCapacity: 5, + ResourceId: objectLike({ + 'Fn::Join': arrayWith(arrayWith( + 'function:', + objectLike({ + 'Fn::Select': arrayWith( + {'Fn::Split': arrayWith( + {Ref: 'Alias325C5727' }), + }, + ), + }), + ':prod', + )), + }), + })); + + expect(stack).to(haveResourceLike('AWS::Lambda::Alias', { + ProvisionedConcurrencyConfig: { + ProvisionedConcurrentExecutions: 10, + }, + })); + test.done(); + }, + + 'validation for utilizationTarget does not fail when using Tokens'(test: Test) { + // GIVEN + const stack = new Stack(); + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const version = fn.addVersion('1', undefined, 'testing'); + + const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version, + provisionedConcurrentExecutions: 10, + }); + + // WHEN + const target = alias.addAutoScaling({ maxCapacity: 5 }); + + target.scaleOnUtilization({utilizationTarget: Lazy.numberValue({ produce: () => 0.95 })}); + + // THEN: no exception + expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { PredefinedMetricType: 'LambdaProvisionedConcurrencyUtilization' }, + TargetValue: 0.95, + }, + + })); + + test.done(); + }, + + 'cannot enable AutoScaling twice on same property'(test: Test): void { + // GIVEN + const stack = new Stack(); + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const version = fn.addVersion('1', undefined, 'testing'); + + const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version, + }); + + // WHEN + alias.addAutoScaling({ maxCapacity: 5 }); + + // THEN + test.throws(() => alias.addAutoScaling({ maxCapacity: 8 }), /AutoScaling already enabled for this alias/); + + test.done(); + }, + + 'error when specifying invalid utilization value when AutoScaling on utilization'(test: Test): void { + // GIVEN + const stack = new Stack(); + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const version = fn.addVersion('1', undefined, 'testing'); + + const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version, + }); + + // WHEN + const target = alias.addAutoScaling({ maxCapacity: 5 }); + + // THEN + test.throws(() => target.scaleOnUtilization({utilizationTarget: 0.95}), /Utilization Target should be between 0.1 and 0.9. Found 0.95/); + test.done(); + }, + + 'can autoscale on a schedule'(test: Test): void { + // GIVEN + const stack = new Stack(); + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const version = fn.addVersion('1', undefined, 'testing'); + + const alias = new lambda.Alias(stack, 'Alias', { + aliasName: 'prod', + version, + }); + + // WHEN + const target = alias.addAutoScaling({ maxCapacity: 5}); + target.scaleOnSchedule('Scheduling', { + schedule: appscaling.Schedule.cron({}), + maxCapacity: 10, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { + ScheduledActions: [ + { + ScalableTargetAction: { MaxCapacity: 10 }, + Schedule: 'cron(* * * * ? *)', + ScheduledActionName: 'Scheduling', + }, + ], + })); + + test.done(); + }, }; From b16025e99dfb9250dc4d1efa50d0e10af5227803 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Tue, 11 Aug 2020 23:45:42 +0200 Subject: [PATCH 30/43] chore(s3-assets): fix typo in local bundling example (#9612) `tryBundler` => `tryBundle` ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-s3-assets/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-s3-assets/README.md b/packages/@aws-cdk/aws-s3-assets/README.md index 86795c8f12598..287406b534559 100644 --- a/packages/@aws-cdk/aws-s3-assets/README.md +++ b/packages/@aws-cdk/aws-s3-assets/README.md @@ -99,7 +99,7 @@ new assets.Asset(this, 'BundledAsset', { path: '/path/to/asset', bundling: { local: { - tryBundler(outputDir: string, options: BundlingOptions) { + tryBundle(outputDir: string, options: BundlingOptions) { if (canRunLocally) { // perform local bundling here return true; From 38aad67c5d2db21cfb3660c1574f7fedde9860dc Mon Sep 17 00:00:00 2001 From: Daniel Neilson <53624638+ddneilson@users.noreply.github.com> Date: Tue, 11 Aug 2020 18:50:10 -0500 Subject: [PATCH 31/43] feat(ecs): Option to encrypt lifecycle hook SNS Topic (#9343) Implements https://github.com/aws/aws-cdk/issues/9230 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/lambda-hook.ts | 16 ++++++- .../aws-autoscaling-hooktargets/package.json | 2 + .../test/hooks.test.ts | 46 +++++++++++++++++++ packages/@aws-cdk/aws-ecs/README.md | 18 ++++++++ packages/@aws-cdk/aws-ecs/lib/cluster.ts | 12 +++++ .../lib/drain-hook/instance-drain-hook.ts | 12 ++++- packages/@aws-cdk/aws-ecs/package.json | 2 + .../@aws-cdk/aws-ecs/test/test.ecs-cluster.ts | 34 +++++++++++++- 8 files changed, 138 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/lib/lambda-hook.ts b/packages/@aws-cdk/aws-autoscaling-hooktargets/lib/lambda-hook.ts index 047a0df140a21..6c3c9cd4caae2 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/lib/lambda-hook.ts +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/lib/lambda-hook.ts @@ -1,4 +1,5 @@ import * as autoscaling from '@aws-cdk/aws-autoscaling'; +import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; import * as subs from '@aws-cdk/aws-sns-subscriptions'; @@ -11,11 +12,22 @@ import { TopicHook } from './topic-hook'; * Internally creates a Topic to make the connection. */ export class FunctionHook implements autoscaling.ILifecycleHookTarget { - constructor(private readonly fn: lambda.IFunction) { + /** + * @param fn Function to invoke in response to a lifecycle event + * @param encryptionKey If provided, this key is used to encrypt the contents of the SNS topic. + */ + constructor(private readonly fn: lambda.IFunction, private readonly encryptionKey?: kms.IKey) { } public bind(scope: Construct, lifecycleHook: autoscaling.ILifecycleHook): autoscaling.LifecycleHookTargetConfig { - const topic = new sns.Topic(scope, 'Topic'); + const topic = new sns.Topic(scope, 'Topic', { + masterKey: this.encryptionKey, + }); + // Per: https://docs.aws.amazon.com/sns/latest/dg/sns-key-management.html#sns-what-permissions-for-sse + // Topic's grantPublish() is in a base class that does not know there is a kms key, and so does not + // grant appropriate permissions to the kms key. We do that here to ensure the correct permissions + // are in place. + this.encryptionKey?.grant(lifecycleHook.role, 'kms:Decrypt', 'kms:GenerateDataKey'); topic.addSubscription(new subs.LambdaSubscription(this.fn)); return new TopicHook(topic).bind(scope, lifecycleHook); } diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index fc353a027cd84..f10c7c41ccb7b 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -69,6 +69,7 @@ "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", @@ -80,6 +81,7 @@ "peerDependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/test/hooks.test.ts b/packages/@aws-cdk/aws-autoscaling-hooktargets/test/hooks.test.ts index 67e6072cdbb16..144dc204122ad 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/test/hooks.test.ts +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/test/hooks.test.ts @@ -1,12 +1,15 @@ import '@aws-cdk/assert/jest'; +import { arrayWith } from '@aws-cdk/assert'; import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sns from '@aws-cdk/aws-sns'; import * as sqs from '@aws-cdk/aws-sqs'; import { Stack } from '@aws-cdk/core'; import * as hooks from '../lib'; + describe('given an AutoScalingGroup', () => { let stack: Stack; let asg: autoscaling.AutoScalingGroup; @@ -77,4 +80,47 @@ describe('given an AutoScalingGroup', () => { Endpoint: { 'Fn::GetAtt': [ 'Fn9270CBC0', 'Arn' ] }, }); }); + + test('can use Lambda function as hook target with encrypted SNS', () => { + // GIVEN + const key = new kms.Key(stack, 'key'); + const fn = new lambda.Function(stack, 'Fn', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.index', + }); + + // WHEN + asg.addLifecycleHook('Trans', { + lifecycleTransition: autoscaling.LifecycleTransition.INSTANCE_LAUNCHING, + notificationTarget: new hooks.FunctionHook(fn, key), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::SNS::Topic', { + KmsMasterKeyId: { + Ref: 'keyFEDD6EC0', + }, + }); + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith( + { + Effect: 'Allow', + Action: [ + 'kms:Decrypt', + 'kms:GenerateDataKey', + ], + Resource: { + 'Fn::GetAtt': [ + 'keyFEDD6EC0', + 'Arn', + ], + }, + }, + ), + }, + }); + }); + }); diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index 75c4ac3698e14..30124b9c838fa 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -146,6 +146,24 @@ cluster.addCapacity('AsgSpot', { }); ``` +### SNS Topic Encryption + +When the `ecs.AddCapacityOptions` that you provide has a non-zero `taskDrainTime` (the default) then an SNS topic and Lambda are created to ensure that the +cluster's instances have been properly drained of tasks before terminating. The SNS Topic is sent the instance-terminating lifecycle event from the AutoScalingGroup, +and the Lambda acts on that event. If you wish to engage [server-side encryption](https://docs.aws.amazon.com/sns/latest/dg/sns-data-encryption.html) for this SNS Topic +then you may do so by providing a KMS key for the `topicEncryptionKey` propery of `ecs.AddCapacityOptions`. + +```ts +// Given +const key = kms.Key(...); +// Then, use that key to encrypt the lifecycle-event SNS Topic. +cluster.addCapacity('ASGEncryptedSNS', { + instanceType: new ec2.InstanceType("t2.xlarge"), + desiredCapacity: 3, + topicEncryptionKey: key, +}); +``` + ## Task definitions A task Definition describes what a single copy of a **task** should look like. diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index 0fff4fd87bd93..228a466101d3d 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -2,6 +2,7 @@ import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as ssm from '@aws-cdk/aws-ssm'; import { Construct, Duration, IResource, Resource, Stack } from '@aws-cdk/core'; @@ -259,6 +260,7 @@ export class Cluster extends Resource implements ICluster { autoScalingGroup, cluster: this, drainTime: options.taskDrainTime, + topicEncryptionKey: options.topicEncryptionKey, }); } } @@ -666,6 +668,16 @@ export interface AddAutoScalingGroupCapacityOptions { * @default false */ readonly spotInstanceDraining?: boolean + + /** + * If {@link AddAutoScalingGroupCapacityOptions.taskDrainTime} is non-zero, then the ECS cluster creates an + * SNS Topic to as part of a system to drain instances of tasks when the instance is being shut down. + * If this property is provided, then this key will be used to encrypt the contents of that SNS Topic. + * See [SNS Data Encryption](https://docs.aws.amazon.com/sns/latest/dg/sns-data-encryption.html) for more information. + * + * @default The SNS Topic will not be encrypted. + */ + readonly topicEncryptionKey?: kms.IKey; } /** diff --git a/packages/@aws-cdk/aws-ecs/lib/drain-hook/instance-drain-hook.ts b/packages/@aws-cdk/aws-ecs/lib/drain-hook/instance-drain-hook.ts index f8062befb60d4..f3e117211cc27 100644 --- a/packages/@aws-cdk/aws-ecs/lib/drain-hook/instance-drain-hook.ts +++ b/packages/@aws-cdk/aws-ecs/lib/drain-hook/instance-drain-hook.ts @@ -1,6 +1,7 @@ import * as autoscaling from '@aws-cdk/aws-autoscaling'; import * as hooks from '@aws-cdk/aws-autoscaling-hooktargets'; import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import * as fs from 'fs'; @@ -33,6 +34,15 @@ export interface InstanceDrainHookProps { * @default Duration.minutes(15) */ drainTime?: cdk.Duration; + + /** + * The InstanceDrainHook creates an SNS topic for the lifecycle hook of the ASG. If provided, then this + * key will be used to encrypt the contents of that SNS Topic. + * See [SNS Data Encryption](https://docs.aws.amazon.com/sns/latest/dg/sns-data-encryption.html) for more information. + * + * @default The SNS Topic will not be encrypted. + */ + topicEncryptionKey?: kms.IKey; } /** @@ -65,7 +75,7 @@ export class InstanceDrainHook extends cdk.Construct { props.autoScalingGroup.addLifecycleHook('DrainHook', { lifecycleTransition: autoscaling.LifecycleTransition.INSTANCE_TERMINATING, defaultResult: autoscaling.DefaultResult.CONTINUE, - notificationTarget: new hooks.FunctionHook(fn), + notificationTarget: new hooks.FunctionHook(fn, props.topicEncryptionKey), heartbeatTimeout: drainTime, }); diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index 8668c5ff06380..2a89eb8abb50f 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -85,6 +85,7 @@ "@aws-cdk/aws-elasticloadbalancing": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", @@ -111,6 +112,7 @@ "@aws-cdk/aws-elasticloadbalancing": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts b/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts index 9eb4ca0ed3bc0..3e3b1eca4c85a 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts +++ b/packages/@aws-cdk/aws-ecs/test/test.ecs-cluster.ts @@ -1,5 +1,12 @@ -import { countResources, expect, haveResource, ResourcePart } from '@aws-cdk/assert'; +import { + countResources, + expect, + haveResource, + haveResourceLike, + ResourcePart, +} from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; import * as cloudmap from '@aws-cdk/aws-servicediscovery'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -501,6 +508,31 @@ export = { test.done(); }, + 'lifecycle hook with encrypted SNS is added correctly'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { + vpc, + }); + const key = new kms.Key(stack, 'Key'); + + // WHEN + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + topicEncryptionKey: key, + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::SNS::Topic', { + KmsMasterKeyId: { + Ref: 'Key961B73FD', + }, + })); + + test.done(); + }, + 'with capacity and cloudmap namespace properties set'(test: Test) { // GIVEN const stack = new cdk.Stack(); From bbf23a86af1aa527999f7df2a92c54bbdf7fa8fe Mon Sep 17 00:00:00 2001 From: Neta Nir Date: Tue, 11 Aug 2020 18:53:35 -0700 Subject: [PATCH 32/43] chore(kms): overridden validate method must be protected (#9616) This PR https://github.com/aws/aws-cdk/pull/9269, implemented `validate()` on the KMS key construct. Since this methods override `Construct` `validate` it must have the same visibility modifier - `protected`. Changing visibility modifier on override methods breaks `jsii-pacmak`, specifically C# packaging.: ``` amazon/CDK/AWS/KMS/Key.cs(97,34): error CS0507: 'Key.Validate()': cannot change access modifiers when overriding 'protected' inherited member 'Construct_.Validate()' [/tmp/npm-packtcwuee/Amazon.CDK.AWS.KMS/Amazon.CDK.AWS.KMS.csproj] ``` ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-kms/lib/key.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-kms/lib/key.ts b/packages/@aws-cdk/aws-kms/lib/key.ts index 8c565776680df..94c65b5c1ee59 100644 --- a/packages/@aws-cdk/aws-kms/lib/key.ts +++ b/packages/@aws-cdk/aws-kms/lib/key.ts @@ -119,7 +119,7 @@ abstract class KeyBase extends Resource implements IKey { return { statementAdded: true, policyDependable: this.policy }; } - public validate(): string[] { + protected validate(): string[] { const errors = super.validate(); errors.push(...this.policy?.validateForResourcePolicy() || []); return errors; From 8edc0c0ca457aec2258a4848508169fdd5b38588 Mon Sep 17 00:00:00 2001 From: Chase Wagoner Date: Tue, 11 Aug 2020 19:33:16 -0700 Subject: [PATCH 33/43] docs(stepfunctions-tasks): fix typo in README (#9498) Following the pattern of other typo PRs, I didn't create an issue prior to opening this. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-stepfunctions-tasks/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 23b9f6660f65e..568e7f957f2e7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -59,8 +59,7 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw ## Task A Task state represents a single unit of work performed by a state machine. In the -CDK, the exact work to be In the CDK, the exact work to be done is determined by -a class that implements `IStepFunctionsTask`. +CDK, the exact work to be done is determined by a class that implements `IStepFunctionsTask`. AWS Step Functions [integrates](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-service-integrations.html) with some AWS services so that you can call API actions, and coordinate executions directly from the Amazon States Language in From a772fe84784e62843ef724a9158fc8cda848c5c9 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Wed, 12 Aug 2020 09:15:20 +0100 Subject: [PATCH 34/43] feat(cognito): better control sms role creation (#9513) - Introduce a property `enableSmsRole` that can be used to override CDK logic and explicitly enable or disable automatic creation of an IAM role for SMS. - Instead of creating the SMS role by default, all of the time, be smart about determining when the role is actually needed. Create the role only if (a) SMS is configured as MFA second factor, (b) sign in via phone number is enabled, or (c) phone verification is required. closes #6943 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../test/integ.graphql-iam.expected.json | 46 --- .../test/integ.graphql.expected.json | 46 --- packages/@aws-cdk/aws-cognito/README.md | 9 +- .../@aws-cdk/aws-cognito/lib/user-pool.ts | 80 ++++-- ...r-pool-client-explicit-props.expected.json | 58 +--- ...nteg.user-pool-domain-cfdist.expected.json | 78 ++--- ...g.user-pool-domain-signinurl.expected.json | 58 +--- .../test/integ.user-pool-idp.expected.json | 58 +--- .../integ.user-pool-signup-code.expected.json | 12 +- .../integ.user-pool-signup-link.expected.json | 12 +- .../test/integ.user-pool.expected.json | 58 +--- .../aws-cognito/test/user-pool.test.ts | 269 +++++++++++++++--- .../test/integ.cognito.lit.expected.json | 46 --- 13 files changed, 358 insertions(+), 472 deletions(-) diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json index e83e633d67676..1d90ae0c15d4b 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json @@ -1,42 +1,5 @@ { "Resources": { - "PoolsmsRoleC3352CE6": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "awsappsyncintegPool5D14B05B" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cognito-idp.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "sns-publish" - } - ] - } - }, "PoolD3F588B8": { "Type": "AWS::Cognito::UserPool", "Properties": { @@ -57,15 +20,6 @@ }, "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", - "SmsConfiguration": { - "ExternalId": "awsappsyncintegPool5D14B05B", - "SnsCallerArn": { - "Fn::GetAtt": [ - "PoolsmsRoleC3352CE6", - "Arn" - ] - } - }, "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolName": "myPool", "VerificationMessageTemplate": { diff --git a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json index dc19df3e4c395..80d03e19f7767 100644 --- a/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json +++ b/packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json @@ -1,42 +1,5 @@ { "Resources": { - "PoolsmsRoleC3352CE6": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "awsappsyncintegPool5D14B05B" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cognito-idp.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "sns-publish" - } - ] - } - }, "PoolD3F588B8": { "Type": "AWS::Cognito::UserPool", "Properties": { @@ -57,15 +20,6 @@ }, "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", - "SmsConfiguration": { - "ExternalId": "awsappsyncintegPool5D14B05B", - "SnsCallerArn": { - "Fn::GetAtt": [ - "PoolsmsRoleC3352CE6", - "Arn" - ] - } - }, "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolName": "myPool", "VerificationMessageTemplate": { diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index 4674fb7570ef8..b4f5a86dc5c26 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -201,8 +201,13 @@ The default value is `false`. Cognito sends various messages to its users via SMS, for different actions, ranging from account verification to marketing. In order to send SMS messages, Cognito needs an IAM role that it can assume, with permissions that allow it -to send SMS messages. By default, CDK will create this IAM role but can also be explicily specified to an existing IAM -role using the `smsRole` property. +to send SMS messages. + +By default, the CDK looks at all of the specified properties (and their defaults when not explicitly specified) and +automatically creates an SMS role, when needed. For example, if MFA second factor by SMS is enabled, the CDK will +create a new role. The `smsRole` property can be used to specify the user supplied role that should be used instead. +Additionally, the property `enableSmsRole` can be used to override the CDK's default behaviour to either enable or +suppress automatic role creation. ```ts import { Role } from '@aws-cdk/aws-iam'; diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index 9a09a6500bb04..ddbc7da3992d3 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -471,6 +471,13 @@ export interface UserPoolProps { */ readonly smsRoleExternalId?: string; + /** + * Setting this would explicitly enable or disable SMS role creation. + * When left unspecified, CDK will determine based on other properties if a role is needed or not. + * @default - CDK will determine based on other properties of the user pool if an SMS role should be created or not. + */ + readonly enableSmsRole?: boolean; + /** * Methods in which a user registers or signs in to a user pool. * Allows either username with aliases OR sign in with email, phone, or both. @@ -835,41 +842,56 @@ export class UserPool extends UserPoolBase { return { usernameAttrs, aliasAttrs, autoVerifyAttrs }; } - private smsConfiguration(props: UserPoolProps): CfnUserPool.SmsConfigurationProperty { + private smsConfiguration(props: UserPoolProps): CfnUserPool.SmsConfigurationProperty | undefined { + if (props.enableSmsRole === false && props.smsRole) { + throw new Error('enableSmsRole cannot be disabled when smsRole is specified'); + } + if (props.smsRole) { return { snsCallerArn: props.smsRole.roleArn, externalId: props.smsRoleExternalId, }; - } else { - const smsRoleExternalId = this.construct.uniqueId.substr(0, 1223); // sts:ExternalId max length of 1224 - const smsRole = props.smsRole ?? new Role(this, 'smsRole', { - assumedBy: new ServicePrincipal('cognito-idp.amazonaws.com', { - conditions: { - StringEquals: { 'sts:ExternalId': smsRoleExternalId }, - }, - }), - inlinePolicies: { - /* - * The UserPool is very particular that it must contain an 'sns:Publish' action as an inline policy. - * Ideally, a conditional that restricts this action to 'sms' protocol needs to be attached, but the UserPool deployment fails validation. - * Seems like a case of being excessively strict. - */ - 'sns-publish': new PolicyDocument({ - statements: [ - new PolicyStatement({ - actions: [ 'sns:Publish' ], - resources: [ '*' ], - }), - ], - }), - }, - }); - return { - externalId: smsRoleExternalId, - snsCallerArn: smsRole.roleArn, - }; } + + if (props.enableSmsRole === false) { + return undefined; + } + + const mfaConfiguration = this.mfaConfiguration(props); + const phoneVerification = props.signInAliases?.phone === true || props.autoVerify?.phone === true; + const roleRequired = mfaConfiguration?.includes('SMS_MFA') || phoneVerification; + if (!roleRequired && props.enableSmsRole === undefined) { + return undefined; + } + + const smsRoleExternalId = this.construct.uniqueId.substr(0, 1223); // sts:ExternalId max length of 1224 + const smsRole = props.smsRole ?? new Role(this, 'smsRole', { + assumedBy: new ServicePrincipal('cognito-idp.amazonaws.com', { + conditions: { + StringEquals: { 'sts:ExternalId': smsRoleExternalId }, + }, + }), + inlinePolicies: { + /* + * The UserPool is very particular that it must contain an 'sns:Publish' action as an inline policy. + * Ideally, a conditional that restricts this action to 'sms' protocol needs to be attached, but the UserPool deployment fails validation. + * Seems like a case of being excessively strict. + */ + 'sns-publish': new PolicyDocument({ + statements: [ + new PolicyStatement({ + actions: [ 'sns:Publish' ], + resources: [ '*' ], + }), + ], + }), + }, + }); + return { + externalId: smsRoleExternalId, + snsCallerArn: smsRole.roleArn, + }; } private mfaConfiguration(props: UserPoolProps): string[] | undefined { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json index 8b5246dfedf58..be2e268a29eac 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-client-explicit-props.expected.json @@ -1,49 +1,18 @@ { "Resources": { - "myuserpoolsmsRole0E16FDD9": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "integuserpoolclientexplicitpropsmyuserpoolFC6541FF" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cognito-idp.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "sns-publish" - } - ] - } - }, "myuserpool01998219": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { @@ -51,15 +20,6 @@ }, "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", - "SmsConfiguration": { - "ExternalId": "integuserpoolclientexplicitpropsmyuserpoolFC6541FF", - "SnsCallerArn": { - "Fn::GetAtt": [ - "myuserpoolsmsRole0E16FDD9", - "Arn" - ] - } - }, "SmsVerificationMessage": "The verification code to your new account is {####}", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json index 511d200ed5d90..368a5945b361b 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-cfdist.expected.json @@ -1,49 +1,18 @@ { "Resources": { - "UserPoolsmsRole4EA729DD": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "integuserpooldomaincfdistUserPool17475E8A" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cognito-idp.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "sns-publish" - } - ] - } - }, "UserPool6BA7E5F2": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { @@ -51,15 +20,6 @@ }, "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", - "SmsConfiguration": { - "ExternalId": "integuserpooldomaincfdistUserPool17475E8A", - "SnsCallerArn": { - "Fn::GetAtt": [ - "UserPoolsmsRole4EA729DD", - "Arn" - ] - } - }, "SmsVerificationMessage": "The verification code to your new account is {####}", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", @@ -176,7 +136,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersa75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4S3BucketC6CBC09E" + "Ref": "AssetParameters8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061S3Bucket67234880" }, "S3Key": { "Fn::Join": [ @@ -189,7 +149,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4S3VersionKeyB194AB23" + "Ref": "AssetParameters8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061S3VersionKey9802AE96" } ] } @@ -202,7 +162,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4S3VersionKeyB194AB23" + "Ref": "AssetParameters8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061S3VersionKey9802AE96" } ] } @@ -244,17 +204,17 @@ } }, "Parameters": { - "AssetParametersa75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4S3BucketC6CBC09E": { + "AssetParameters8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061S3Bucket67234880": { "Type": "String", - "Description": "S3 bucket for asset \"a75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4\"" + "Description": "S3 bucket for asset \"8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061\"" }, - "AssetParametersa75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4S3VersionKeyB194AB23": { + "AssetParameters8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061S3VersionKey9802AE96": { "Type": "String", - "Description": "S3 key for asset version \"a75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4\"" + "Description": "S3 key for asset version \"8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061\"" }, - "AssetParametersa75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4ArtifactHashBE5BD63C": { + "AssetParameters8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061ArtifactHash9212BF97": { "Type": "String", - "Description": "Artifact hash for asset \"a75563f489fb6bc4064bc85b91ef607f671326e647bcd9d9bcab0731de62edd4\"" + "Description": "Artifact hash for asset \"8ae75ec4aaae0510b0918d3a69fac5c978d780ae0d60bb94c65c7f5b4c498061\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json index 6bb3d7edab140..694cf43b5f5ea 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-domain-signinurl.expected.json @@ -1,49 +1,18 @@ { "Resources": { - "UserPoolsmsRole4EA729DD": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "integuserpooldomainsigninurlUserPool1325E89F" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cognito-idp.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "sns-publish" - } - ] - } - }, "UserPool6BA7E5F2": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { @@ -51,15 +20,6 @@ }, "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", - "SmsConfiguration": { - "ExternalId": "integuserpooldomainsigninurlUserPool1325E89F", - "SnsCallerArn": { - "Fn::GetAtt": [ - "UserPoolsmsRole4EA729DD", - "Arn" - ] - } - }, "SmsVerificationMessage": "The verification code to your new account is {####}", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.expected.json index 3fa00974541cf..e68a262eb7ee3 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.expected.json @@ -1,49 +1,18 @@ { "Resources": { - "poolsmsRole04048F13": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "integuserpoolidppoolAE0BD80C" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cognito-idp.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "sns-publish" - } - ] - } - }, "pool056F3F7E": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { @@ -51,15 +20,6 @@ }, "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", - "SmsConfiguration": { - "ExternalId": "integuserpoolidppoolAE0BD80C", - "SnsCallerArn": { - "Fn::GetAtt": [ - "poolsmsRole04048F13", - "Arn" - ] - } - }, "SmsVerificationMessage": "The verification code to your new account is {####}", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json index 90d858978f043..5cc13052434f2 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-code.expected.json @@ -40,10 +40,16 @@ "myuserpool01998219": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json index 45661be1e0766..53c9f89ed8031 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-signup-link.expected.json @@ -40,10 +40,16 @@ "myuserpool01998219": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json index f2beef72d6eb4..85214615c050d 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool.expected.json @@ -1,49 +1,18 @@ { "Resources": { - "myuserpoolsmsRole0E16FDD9": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "integuserpoolmyuserpoolDA38443C" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cognito-idp.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "sns-publish" - } - ] - } - }, "myuserpool01998219": { "Type": "AWS::Cognito::UserPool", "Properties": { - "AccountRecoverySetting": { + "AccountRecoverySetting": { "RecoveryMechanisms": [ - { "Name": "verified_phone_number", "Priority": 1 }, - { "Name": "verified_email", "Priority": 2 } + { + "Name": "verified_phone_number", + "Priority": 1 + }, + { + "Name": "verified_email", + "Priority": 2 + } ] }, "AdminCreateUserConfig": { @@ -51,15 +20,6 @@ }, "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", - "SmsConfiguration": { - "ExternalId": "integuserpoolmyuserpoolDA38443C", - "SnsCallerArn": { - "Fn::GetAtt": [ - "myuserpoolsmsRole0E16FDD9", - "Arn" - ] - } - }, "SmsVerificationMessage": "The verification code to your new account is {####}", "UserPoolName": "MyUserPool", "VerificationMessageTemplate": { diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index cf24bed751e34..1be015f803baa 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -1,6 +1,6 @@ import '@aws-cdk/assert/jest'; import { ABSENT } from '@aws-cdk/assert/lib/assertions/have-resource'; -import { Role } from '@aws-cdk/aws-iam'; +import { Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { CfnParameter, Construct, Duration, Stack, Tag } from '@aws-cdk/core'; import { AccountRecovery, Mfa, NumberAttribute, StringAttribute, UserPool, UserPoolIdentityProvider, UserPoolOperation, VerificationEmailStyle } from '../lib'; @@ -28,49 +28,9 @@ describe('User Pool', () => { EmailSubject: 'Verify your new account', SmsMessage: 'The verification code to your new account is {####}', }, - SmsConfiguration: { - SnsCallerArn: { - 'Fn::GetAtt': [ 'PoolsmsRoleC3352CE6', 'Arn' ], - }, - ExternalId: 'Pool', - }, + SmsConfiguration: ABSENT, lambdaTriggers: ABSENT, }); - - expect(stack).toHaveResource('AWS::IAM::Role', { - AssumeRolePolicyDocument: { - Statement: [ - { - Action: 'sts:AssumeRole', - Condition: { - StringEquals: { - 'sts:ExternalId': 'Pool', - }, - }, - Effect: 'Allow', - Principal: { - Service: 'cognito-idp.amazonaws.com', - }, - }, - ], - Version: '2012-10-17', - }, - Policies: [ - { - PolicyDocument: { - Statement: [ - { - Action: 'sns:Publish', - Effect: 'Allow', - Resource: '*', - }, - ], - Version: '2012-10-17', - }, - PolicyName: 'sns-publish', - }, - ], - }); }); test('self sign up option is correctly configured', () => { @@ -1085,6 +1045,231 @@ describe('User Pool', () => { }); }); }); + + describe('sms roles', () => { + test('default', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new UserPool(stack, 'pool'); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: ABSENT, + }); + }); + + test('smsRole and smsExternalId is set', () => { + // GIVEN + const stack = new Stack(); + const smsRole = new Role(stack, 'smsRole', { + assumedBy: new ServicePrincipal('service.amazonaws.com'), + }); + + // WHEN + new UserPool(stack, 'pool', { + smsRole, + smsRoleExternalId: 'role-external-id', + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: { + ExternalId: 'role-external-id', + SnsCallerArn: { 'Fn::GetAtt': [ 'smsRoleA4587CE8', 'Arn' ] }, + }, + }); + }); + + test('setting enableSmsRole creates an sms role', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new UserPool(stack, 'pool', { + enableSmsRole: true, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: { + ExternalId: 'pool', + SnsCallerArn: { 'Fn::GetAtt': [ 'poolsmsRole04048F13', 'Arn' ] }, + }, + }); + expect(stack).toHaveResource('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Condition: { + StringEquals: { + 'sts:ExternalId': 'pool', + }, + }, + Effect: 'Allow', + Principal: { + Service: 'cognito-idp.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + Policies: [ + { + PolicyDocument: { + Statement: [ + { + Action: 'sns:Publish', + Effect: 'Allow', + Resource: '*', + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'sns-publish', + }, + ], + }); + }); + + test('auto sms role is not created when MFA and phoneVerification is off', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new UserPool(stack, 'pool', { + mfa: Mfa.OFF, + signInAliases: { + phone: false, + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: ABSENT, + }); + }); + + test('auto sms role is not created when OTP-based MFA is enabled and phoneVerification is off', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new UserPool(stack, 'pool', { + mfa: Mfa.REQUIRED, + mfaSecondFactor: { + otp: true, + sms: false, + }, + signInAliases: { + phone: false, + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: ABSENT, + }); + }); + + test('auto sms role is created when phone verification is turned on', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new UserPool(stack, 'pool', { + mfa: Mfa.OFF, + signInAliases: { phone: true }, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: { + ExternalId: 'pool', + SnsCallerArn: { 'Fn::GetAtt': [ 'poolsmsRole04048F13', 'Arn' ] }, + }, + }); + }); + + test('auto sms role is created when phone auto-verification is set', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new UserPool(stack, 'pool', { + mfa: Mfa.OFF, + signInAliases: { phone: false }, + autoVerify: { phone: true }, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: { + ExternalId: 'pool', + SnsCallerArn: { 'Fn::GetAtt': [ 'poolsmsRole04048F13', 'Arn' ] }, + }, + }); + }); + + test('auto sms role is created when MFA is turned on', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new UserPool(stack, 'pool', { + mfa: Mfa.REQUIRED, + mfaSecondFactor: { + sms: true, + otp: false, + }, + signInAliases: { + phone: false, + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: { + ExternalId: 'pool', + SnsCallerArn: { 'Fn::GetAtt': [ 'poolsmsRole04048F13', 'Arn' ] }, + }, + }); + }); + + test('auto sms role is not created when enableSmsRole is unset, even when MFA is configured', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new UserPool(stack, 'pool', { + mfa: Mfa.REQUIRED, + mfaSecondFactor: { + sms: true, + otp: false, + }, + enableSmsRole: false, + }); + + // THEN + expect(stack).toHaveResource('AWS::Cognito::UserPool', { + SmsConfiguration: ABSENT, + }); + }); + + test('throws an error when smsRole is specified but enableSmsRole is unset', () => { + const stack = new Stack(); + const smsRole = new Role(stack, 'smsRole', { + assumedBy: new ServicePrincipal('service.amazonaws.com'), + }); + + expect(() => new UserPool(stack, 'pool', { + smsRole, + enableSmsRole: false, + })).toThrow(/enableSmsRole cannot be disabled/); + }); + }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json index e35271c92c173..be3c5a7fe88d8 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.expected.json @@ -453,43 +453,6 @@ ] } }, - "UserPoolsmsRole4EA729DD": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "integcognitoUserPool7BB79D76" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cognito-idp.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "sns:Publish", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "sns-publish" - } - ] - } - }, "UserPool6BA7E5F2": { "Type": "AWS::Cognito::UserPool", "Properties": { @@ -504,15 +467,6 @@ }, "EmailVerificationMessage": "The verification code to your new account is {####}", "EmailVerificationSubject": "Verify your new account", - "SmsConfiguration": { - "ExternalId": "integcognitoUserPool7BB79D76", - "SnsCallerArn": { - "Fn::GetAtt": [ - "UserPoolsmsRole4EA729DD", - "Arn" - ] - } - }, "SmsVerificationMessage": "The verification code to your new account is {####}", "VerificationMessageTemplate": { "DefaultEmailOption": "CONFIRM_WITH_CODE", From 398f8720fac6ae7eb663a36c87c1f8f11aa89045 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 12 Aug 2020 12:25:57 +0200 Subject: [PATCH 35/43] feat: "stack relative exports" flag (#9604) Previously, CloudFormation `Exports` generated by cross-stack references were named after a static part of the construct tree (everything after the 2nd component). This must have been left over from the days when the construct tree structure was strictly ``` App -> Stack -> Other constructs... ``` And so it would skip the `App` and `Stack` levels, leaving a construct path that was relative to the containing stack. For a while, `Stacks` have been able to occur at multiple levels, but this code was never updated. The result is that this now produces considerable breakage if stacks are moved around (motivating example: moving `Stack`s into `Stages` for the benefit of deploying them using CDK Pipelines). This behavior cannot be fixed without breaking most CDK applications that currently exist, so it is being introduced as a feature flag, which should be enabled on new applications and made default in V2, but for now is opt-in and to be enabled by people migrating their existing apps onto CDK Pipelines. The new behavior is to explicitly build the export name relative to the containing Stack, as opposed to relative to construct tree level 2. > Note that giving the new containing Stage the construct ID `"Default"` > is not good enough, as the new construct tree leveling looks like: > > ``` > App -> Stage -> Stack -> [Construct IDs] > "Default" / "Stack" / "IDs/I/care/about" > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ current algo will use these > ^^^^^^^^^^^^^^^^^ I actually want these > ``` > i.e., `"Default"` does not occur at a level where it will be properly ignored. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/core/lib/private/refs.ts | 11 ++++++- packages/@aws-cdk/core/test/test.stack.ts | 37 ++++++++++++++++++++++ packages/@aws-cdk/cx-api/lib/features.ts | 11 +++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/core/lib/private/refs.ts b/packages/@aws-cdk/core/lib/private/refs.ts index cfe56226aa130..43c6c4e0a8422 100644 --- a/packages/@aws-cdk/core/lib/private/refs.ts +++ b/packages/@aws-cdk/core/lib/private/refs.ts @@ -1,6 +1,8 @@ // ---------------------------------------------------- // CROSS REFERENCES // ---------------------------------------------------- +import * as cxapi from '@aws-cdk/cx-api'; + import { CfnElement } from '../cfn-element'; import { CfnOutput } from '../cfn-output'; import { CfnParameter } from '../cfn-parameter'; @@ -199,8 +201,15 @@ function getCreateExportsScope(stack: Stack) { } function generateExportName(stackExports: Construct, id: string) { + const stackRelativeExports = stackExports.construct.tryGetContext(cxapi.STACK_RELATIVE_EXPORTS_CONTEXT); const stack = Stack.of(stackExports); - const components = [...stackExports.construct.scopes.slice(2).map(c => c.construct.id), id]; + + const components = [ + ...stackExports.construct.scopes + .slice(stackRelativeExports ? stack.construct.scopes.length : 2) + .map(c => c.construct.id), + id, + ]; const prefix = stack.stackName ? stack.stackName + ':' : ''; const exportName = prefix + makeUniqueId(components); return exportName; diff --git a/packages/@aws-cdk/core/test/test.stack.ts b/packages/@aws-cdk/core/test/test.stack.ts index 08f86c1eba7c3..b24717886a5b0 100644 --- a/packages/@aws-cdk/core/test/test.stack.ts +++ b/packages/@aws-cdk/core/test/test.stack.ts @@ -249,6 +249,43 @@ export = { test.done(); }, + 'Cross-stack reference export names are relative to the stack (when the flag is set)'(test: Test) { + // GIVEN + const app = new App({ + context: { + '@aws-cdk/core:stackRelativeExports': 'true', + }, + }); + const indifferentScope = new Construct(app, 'ExtraScope'); + + const stack1 = new Stack(indifferentScope, 'Stack1', { + stackName: 'Stack1', + }); + const resource1 = new CfnResource(stack1, 'Resource', { type: 'BLA' }); + const stack2 = new Stack(indifferentScope, 'Stack2'); + + // WHEN - used in another resource + new CfnResource(stack2, 'SomeResource', { type: 'AWS::Some::Resource', properties: { + someProperty: new Intrinsic(resource1.ref), + }}); + + // THEN + const assembly = app.synth(); + const template2 = assembly.getStackByName(stack2.stackName).template; + + test.deepEqual(template2, { + Resources: { + SomeResource: { + Type: 'AWS::Some::Resource', + Properties: { + someProperty: { 'Fn::ImportValue': 'Stack1:ExportsOutputRefResource1D5D905A' }, + }, + }, + }, + }); + test.done(); + }, + 'cross-stack references in lazy tokens work'(test: Test) { // GIVEN const app = new App(); diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index cc3f94f91e23d..5483e64f92021 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -34,6 +34,16 @@ export const ENABLE_DIFF_NO_FAIL = ENABLE_DIFF_NO_FAIL_CONTEXT; */ export const NEW_STYLE_STACK_SYNTHESIS_CONTEXT = '@aws-cdk/core:newStyleStackSynthesis'; +/** + * Name exports based on the construct paths relative to the stack, rather than the global construct path + * + * Combined with the stack name this relative construct path is good enough to + * ensure uniqueness, and makes the export names robust against refactoring + * the location of the stack in the construct tree (specifically, moving the Stack + * into a Stage). + */ +export const STACK_RELATIVE_EXPORTS_CONTEXT = '@aws-cdk/core:stackRelativeExports'; + /** * This map includes context keys and values for feature flags that enable * capabilities "from the future", which we could not introduce as the default @@ -50,6 +60,7 @@ export const NEW_STYLE_STACK_SYNTHESIS_CONTEXT = '@aws-cdk/core:newStyleStackSyn export const FUTURE_FLAGS = { [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: 'true', [ENABLE_DIFF_NO_FAIL_CONTEXT]: 'true', + [STACK_RELATIVE_EXPORTS_CONTEXT]: 'true', // We will advertise this flag when the feature is complete // [NEW_STYLE_STACK_SYNTHESIS]: 'true', From ce34c0369e0edf8eedb45c71b1767ddc73c7b6a7 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 12 Aug 2020 16:50:39 +0200 Subject: [PATCH 36/43] chore: revert introduction of "Construct.construct" member (#9637) The addition of the new `construct` member leads to problems in the C# code generation, where it would properly be called `Construct.Construct`: a member may not have the same name as the class, because that is the name of the class constructor (see https://github.com/aws/jsii/issues/1880). Our build is currently broken because of this. Revert the renames to unblock the build, giving us the opportunity to tackle this problem afresh next week. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/pipeline-deploy-stack-action.ts | 2 +- .../test/test.pipeline-deploy-stack-action.ts | 2 +- packages/@aws-cdk/assert/lib/synth-utils.ts | 2 +- packages/@aws-cdk/assets/test/test.staging.ts | 2 +- packages/@aws-cdk/aws-amplify/lib/app.ts | 2 +- .../aws-apigateway/lib/authorizers/lambda.ts | 10 +- .../@aws-cdk/aws-apigateway/lib/deployment.ts | 6 +- .../aws-apigateway/lib/domain-name.ts | 2 +- .../aws-apigateway/lib/gateway-response.ts | 2 +- .../aws-apigateway/lib/integrations/lambda.ts | 4 +- .../@aws-cdk/aws-apigateway/lib/method.ts | 2 +- packages/@aws-cdk/aws-apigateway/lib/model.ts | 2 +- .../aws-apigateway/lib/requestvalidator.ts | 2 +- .../@aws-cdk/aws-apigateway/lib/resource.ts | 4 +- .../@aws-cdk/aws-apigateway/lib/restapi.ts | 6 +- .../@aws-cdk/aws-apigateway/lib/usage-plan.ts | 2 +- .../@aws-cdk/aws-apigateway/lib/vpc-link.ts | 2 +- .../test/integ.restapi-import.lit.ts | 2 +- .../aws-apigateway/test/test.deployment.ts | 2 +- .../aws-apigateway/test/test.method.ts | 8 +- .../aws-apigateway/test/test.model.ts | 4 +- .../test/test.requestvalidator.ts | 4 +- .../aws-apigateway/test/test.restapi.ts | 10 +- .../aws-apigatewayv2/lib/http/api-mapping.ts | 4 +- .../@aws-cdk/aws-apigatewayv2/lib/http/api.ts | 2 +- .../lib/http/integrations/lambda.ts | 2 +- .../aws-apigatewayv2/lib/http/route.ts | 2 +- .../aws-apigatewayv2/lib/http/stage.ts | 2 +- .../lib/step-scaling-action.ts | 2 +- .../lib/target-tracking-scaling-policy.ts | 2 +- packages/@aws-cdk/aws-appmesh/lib/mesh.ts | 2 +- packages/@aws-cdk/aws-appmesh/lib/route.ts | 2 +- .../@aws-cdk/aws-appmesh/lib/virtual-node.ts | 2 +- .../aws-appmesh/lib/virtual-router.ts | 2 +- .../aws-appmesh/lib/virtual-service.ts | 2 +- .../aws-autoscaling/lib/auto-scaling-group.ts | 12 +- .../aws-autoscaling/lib/lifecycle-hook.ts | 2 +- .../test/auto-scaling-group.test.ts | 14 +- packages/@aws-cdk/aws-backup/lib/plan.ts | 2 +- packages/@aws-cdk/aws-backup/lib/selection.ts | 4 +- packages/@aws-cdk/aws-backup/lib/vault.ts | 2 +- .../aws-batch/lib/compute-environment.ts | 2 +- .../test/compute-environment.test.ts | 4 +- .../aws-certificatemanager/lib/util.ts | 2 +- .../aws-cloudformation/test/test.deps.ts | 2 +- .../test/test.nested-stack.ts | 4 +- .../aws-cloudfront/lib/distribution.ts | 4 +- .../aws-cloudfront/lib/web_distribution.ts | 2 +- .../test/web_distribution.test.ts | 2 +- .../@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts | 4 +- .../aws-cloudwatch/lib/composite-alarm.ts | 2 +- .../@aws-cdk/aws-codebuild/lib/project.ts | 4 +- .../@aws-cdk/aws-codecommit/lib/repository.ts | 2 +- .../lib/lambda/deployment-group.ts | 2 +- .../lib/profiling-group.ts | 2 +- .../lib/cloudformation/pipeline-actions.ts | 4 +- .../lib/codecommit/source-action.ts | 2 +- .../lib/ecr/source-action.ts | 2 +- .../lib/s3/source-action.ts | 4 +- .../test.cloudformation-pipeline-actions.ts | 2 +- .../test/test.pipeline.ts | 4 +- .../@aws-cdk/aws-codepipeline/lib/pipeline.ts | 14 +- .../aws-codepipeline/test/test.pipeline.ts | 2 +- .../@aws-cdk/aws-cognito/lib/user-pool.ts | 2 +- packages/@aws-cdk/aws-config/lib/rule.ts | 2 +- packages/@aws-cdk/aws-docdb/lib/cluster.ts | 6 +- .../@aws-cdk/aws-docdb/test/cluster.test.ts | 2 +- .../@aws-cdk/aws-docdb/test/instance.test.ts | 2 +- .../lib/aws-dynamodb-global.ts | 2 +- .../test/test.dynamodb.global.ts | 6 +- .../aws-dynamodb/lib/replica-provider.ts | 2 +- packages/@aws-cdk/aws-dynamodb/lib/table.ts | 18 +- .../aws-dynamodb/test/dynamodb.test.ts | 8 +- .../test/integ.dynamodb.ondemand.ts | 2 +- .../aws-dynamodb/test/integ.dynamodb.sse.ts | 2 +- .../aws-dynamodb/test/integ.dynamodb.ts | 2 +- packages/@aws-cdk/aws-ec2/lib/instance.ts | 10 +- .../@aws-cdk/aws-ec2/lib/security-group.ts | 10 +- packages/@aws-cdk/aws-ec2/lib/user-data.ts | 4 +- packages/@aws-cdk/aws-ec2/lib/util.ts | 2 +- packages/@aws-cdk/aws-ec2/lib/volume.ts | 4 +- packages/@aws-cdk/aws-ec2/lib/vpc.ts | 24 +-- .../@aws-cdk/aws-ec2/test/instance.test.ts | 8 +- .../aws-ec2/test/vpc-endpoint.test.ts | 10 +- packages/@aws-cdk/aws-ec2/test/vpc.test.ts | 12 +- .../aws-ecr-assets/lib/image-asset.ts | 2 +- .../aws-ecr-assets/test/test.image-asset.ts | 6 +- .../application-load-balanced-service-base.ts | 4 +- ...ion-multiple-target-groups-service-base.ts | 14 +- .../network-load-balanced-service-base.ts | 4 +- ...ork-multiple-target-groups-service-base.ts | 12 +- .../lib/base/queue-processing-service-base.ts | 6 +- .../lib/base/scheduled-task-base.ts | 4 +- .../application-load-balanced-ecs-service.ts | 2 +- .../ecs/network-load-balanced-ecs-service.ts | 2 +- .../lib/ecs/scheduled-ecs-task.ts | 2 +- ...plication-load-balanced-fargate-service.ts | 2 +- .../network-load-balanced-fargate-service.ts | 2 +- .../lib/fargate/scheduled-fargate-task.ts | 2 +- .../aws-ecs-patterns/test/ec2/test.l3s-v2.ts | 12 +- .../integ.load-balanced-fargate-service.ts | 10 +- .../test.load-balanced-fargate-service.ts | 15 +- .../@aws-cdk/aws-ecs/lib/base/base-service.ts | 4 +- .../aws-ecs/lib/base/task-definition.ts | 2 +- .../aws-ecs/lib/container-definition.ts | 4 +- .../@aws-cdk/aws-ecs/lib/images/repository.ts | 2 +- .../aws-ecs/test/ec2/test.ec2-service.ts | 2 +- .../test/ec2/test.ec2-task-definition.ts | 4 +- .../test/fargate/test.fargate-service.ts | 2 +- .../@aws-cdk/aws-efs/lib/efs-file-system.ts | 2 +- .../aws-efs/test/efs-file-system.test.ts | 2 +- .../@aws-cdk/aws-eks-legacy/lib/cluster.ts | 6 +- .../@aws-cdk/aws-eks-legacy/lib/helm-chart.ts | 4 +- .../aws-eks-legacy/lib/kubectl-layer.ts | 4 +- .../@aws-cdk/aws-eks-legacy/lib/user-data.ts | 2 +- .../aws-eks/lib/cluster-resource-provider.ts | 2 +- .../@aws-cdk/aws-eks/lib/cluster-resource.ts | 2 +- packages/@aws-cdk/aws-eks/lib/cluster.ts | 14 +- .../@aws-cdk/aws-eks/lib/fargate-profile.ts | 2 +- packages/@aws-cdk/aws-eks/lib/helm-chart.ts | 2 +- .../@aws-cdk/aws-eks/lib/kubectl-layer.ts | 4 +- .../@aws-cdk/aws-eks/lib/legacy-cluster.ts | 4 +- .../@aws-cdk/aws-eks/lib/service-account.ts | 2 +- packages/@aws-cdk/aws-eks/lib/user-data.ts | 2 +- .../aws-eks/test/integ.eks-cluster.ts | 2 +- .../@aws-cdk/aws-eks/test/test.cluster.ts | 14 +- .../lib/load-balancer.ts | 2 +- .../test/test.loadbalancer.ts | 2 +- .../test/integ.cognito.lit.ts | 2 +- .../lib/alb/application-listener-rule.ts | 2 +- .../lib/alb/application-load-balancer.ts | 6 +- .../lib/alb/application-target-group.ts | 4 +- .../lib/nlb/network-load-balancer.ts | 4 +- .../lib/shared/base-listener.ts | 2 +- .../lib/shared/base-load-balancer.ts | 4 +- .../lib/shared/base-target-group.ts | 2 +- .../test/alb/test.listener.ts | 2 +- .../test/integ.alb.dualstack.ts | 4 +- .../test/integ.nlb.ts | 2 +- .../test/nlb/test.listener.ts | 2 +- .../aws-events-targets/lib/aws-api.ts | 2 +- .../@aws-cdk/aws-events-targets/lib/batch.ts | 2 +- .../aws-events-targets/lib/ecs-task.ts | 4 +- .../@aws-cdk/aws-events-targets/lib/util.ts | 4 +- .../test/codepipeline/pipeline.test.ts | 2 +- packages/@aws-cdk/aws-events/lib/event-bus.ts | 2 +- packages/@aws-cdk/aws-events/lib/rule.ts | 8 +- .../@aws-cdk/aws-events/test/test.rule.ts | 6 +- packages/@aws-cdk/aws-glue/lib/table.ts | 2 +- packages/@aws-cdk/aws-glue/test/table.test.ts | 4 +- packages/@aws-cdk/aws-iam/lib/grant.ts | 4 +- packages/@aws-cdk/aws-iam/lib/role.ts | 2 +- .../@aws-cdk/aws-iam/lib/unknown-principal.ts | 4 +- .../aws-iam/test/escape-hatch.test.ts | 6 +- packages/@aws-cdk/aws-iam/test/policy.test.ts | 6 +- .../aws-iam/test/role.from-role-arn.test.ts | 2 +- packages/@aws-cdk/aws-kinesis/lib/stream.ts | 4 +- packages/@aws-cdk/aws-kms/test/test.key.ts | 6 +- .../aws-lambda-event-sources/lib/api.ts | 4 +- .../aws-lambda-event-sources/lib/dynamodb.ts | 4 +- .../aws-lambda-event-sources/lib/kinesis.ts | 2 +- .../aws-lambda-event-sources/lib/sqs.ts | 2 +- .../@aws-cdk/aws-lambda/lib/function-base.ts | 9 +- .../@aws-cdk/aws-lambda/lib/function-hash.ts | 2 +- packages/@aws-cdk/aws-lambda/lib/function.ts | 10 +- .../aws-lambda/lib/singleton-lambda.ts | 6 +- .../@aws-cdk/aws-lambda/test/test.code.ts | 2 +- .../@aws-cdk/aws-lambda/test/test.layers.ts | 2 +- .../aws-logs-destinations/lib/kinesis.ts | 2 +- packages/@aws-cdk/aws-rds/lib/cluster.ts | 6 +- packages/@aws-cdk/aws-rds/lib/instance.ts | 6 +- packages/@aws-cdk/aws-rds/lib/proxy.ts | 4 +- .../@aws-cdk/aws-rds/test/test.cluster.ts | 2 +- packages/@aws-cdk/aws-redshift/lib/cluster.ts | 2 +- .../aws-redshift/test/cluster.test.ts | 2 +- .../lib/cloudfront-target.ts | 2 +- .../lib/interface-vpc-endpoint-target.ts | 2 +- .../test/test.hosted-zone-provider.ts | 4 +- .../@aws-cdk/aws-route53/test/test.util.ts | 4 - packages/@aws-cdk/aws-s3-assets/lib/asset.ts | 2 +- .../@aws-cdk/aws-s3-assets/test/asset.test.ts | 6 +- .../@aws-cdk/aws-s3-deployment/lib/source.ts | 2 +- .../aws-s3-notifications/lib/lambda.ts | 2 +- .../test/notifications.test.ts | 2 +- packages/@aws-cdk/aws-s3/lib/bucket.ts | 4 +- .../notifications-resource-handler.ts | 4 +- .../notifications-resource.ts | 2 +- packages/@aws-cdk/aws-s3/test/test.aspect.ts | 6 +- .../aws-secretsmanager/lib/secret-rotation.ts | 2 +- .../@aws-cdk/aws-secretsmanager/lib/secret.ts | 2 +- .../lib/alias-target-instance.ts | 2 +- .../aws-servicediscovery/lib/instance.ts | 2 +- .../@aws-cdk/aws-ses-actions/lib/lambda.ts | 4 +- packages/@aws-cdk/aws-ses-actions/lib/s3.ts | 6 +- .../aws-sns-subscriptions/lib/lambda.ts | 4 +- .../@aws-cdk/aws-sns-subscriptions/lib/sqs.ts | 2 +- packages/@aws-cdk/aws-sns/lib/topic-base.ts | 8 +- packages/@aws-cdk/aws-sqs/lib/queue.ts | 2 +- packages/@aws-cdk/aws-ssm/lib/parameter.ts | 4 +- .../aws-ssm/test/integ.parameter-arns.ts | 2 +- .../lib/ecs/run-ecs-task-base.ts | 2 +- .../lib/ecs/run-task.ts | 2 +- .../aws-stepfunctions/lib/activity.ts | 2 +- .../lib/state-machine-fragment.ts | 2 +- .../aws-stepfunctions/lib/state-machine.ts | 2 +- .../aws-stepfunctions/lib/states/state.ts | 4 +- .../test/valid-templates.test.ts | 4 +- packages/@aws-cdk/core/README.md | 10 +- packages/@aws-cdk/core/lib/annotations.ts | 2 +- packages/@aws-cdk/core/lib/app.ts | 8 +- packages/@aws-cdk/core/lib/aspect.ts | 4 +- packages/@aws-cdk/core/lib/asset-staging.ts | 8 +- packages/@aws-cdk/core/lib/cfn-element.ts | 6 +- packages/@aws-cdk/core/lib/cfn-output.ts | 2 +- packages/@aws-cdk/core/lib/cfn-parse.ts | 2 +- packages/@aws-cdk/core/lib/cfn-resource.ts | 10 +- .../@aws-cdk/core/lib/construct-compat.ts | 25 +-- .../@aws-cdk/core/lib/context-provider.ts | 2 +- .../custom-resource-provider.ts | 2 +- packages/@aws-cdk/core/lib/deps.ts | 6 +- packages/@aws-cdk/core/lib/nested-stack.ts | 4 +- .../core/lib/private/cfn-reference.ts | 7 +- .../lib/private/physical-name-generator.ts | 6 +- .../@aws-cdk/core/lib/private/prepare-app.ts | 6 +- packages/@aws-cdk/core/lib/private/refs.ts | 28 +-- .../@aws-cdk/core/lib/private/synthesis.ts | 10 +- .../core/lib/private/tree-metadata.ts | 10 +- packages/@aws-cdk/core/lib/resource.ts | 2 +- .../core/lib/stack-synthesizers/_shared.ts | 12 +- .../stack-synthesizers/default-synthesizer.ts | 2 +- .../core/lib/stack-synthesizers/legacy.ts | 8 +- packages/@aws-cdk/core/lib/stack.ts | 32 +-- packages/@aws-cdk/core/lib/stage.ts | 10 +- .../test.custom-resource-provider.ts | 2 +- .../core/test/private/test.tree-metadata.ts | 4 +- packages/@aws-cdk/core/test/test.app.ts | 28 +-- packages/@aws-cdk/core/test/test.aspect.ts | 22 +- packages/@aws-cdk/core/test/test.assets.ts | 10 +- .../@aws-cdk/core/test/test.cfn-resource.ts | 2 +- packages/@aws-cdk/core/test/test.construct.ts | 202 +++++++++--------- packages/@aws-cdk/core/test/test.context.ts | 8 +- .../@aws-cdk/core/test/test.logical-id.ts | 6 +- packages/@aws-cdk/core/test/test.resource.ts | 14 +- packages/@aws-cdk/core/test/test.stack.ts | 10 +- packages/@aws-cdk/core/test/test.stage.ts | 6 +- packages/@aws-cdk/core/test/test.staging.ts | 2 +- packages/@aws-cdk/core/test/test.synthesis.ts | 2 +- packages/@aws-cdk/core/test/test.util.ts | 4 +- .../lib/provider-framework/provider.ts | 2 +- .../waiter-state-machine.ts | 2 +- .../integ.aws-custom-resource.ts | 2 +- .../test/provider-framework/integ.provider.ts | 2 +- .../integration-test-fixtures/s3-assert.ts | 2 +- .../integration-test-fixtures/s3-file.ts | 2 +- .../lib/actions/deploy-cdk-stack-action.ts | 4 +- packages/@aws-cdk/pipelines/lib/pipeline.ts | 6 +- .../lib/private/construct-internals.ts | 4 +- packages/@aws-cdk/pipelines/lib/stage.ts | 2 +- .../test/cross-environment-infra.test.ts | 2 +- packages/decdk/lib/declarative-stack.ts | 8 +- 260 files changed, 701 insertions(+), 709 deletions(-) diff --git a/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts index 7f22106e844f7..03685cfc9c413 100644 --- a/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts @@ -115,7 +115,7 @@ export class PipelineDeployStackAction implements codepipeline.IAction { constructor(props: PipelineDeployStackActionProps) { this.stack = props.stack; - const assets = this.stack.construct.metadata.filter(md => md.type === cxschema.ArtifactMetadataEntryType.ASSET); + const assets = this.stack.node.metadata.filter(md => md.type === cxschema.ArtifactMetadataEntryType.ASSET); if (assets.length > 0) { // FIXME: Implement the necessary actions to publish assets throw new Error(`Cannot deploy the stack ${this.stack.stackName} because it references ${assets.length} asset(s)`); diff --git a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts index 641e12331fdbc..918279b480b30 100644 --- a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts @@ -390,7 +390,7 @@ export = nodeunit.testCase({ const deployedStack = new cdk.Stack(app, 'DeployedStack'); for (let i = 0 ; i < assetCount ; i++) { - deployedStack.construct.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, {}); + deployedStack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, {}); } test.throws(() => { diff --git a/packages/@aws-cdk/assert/lib/synth-utils.ts b/packages/@aws-cdk/assert/lib/synth-utils.ts index dfd73b371dd65..bb8d9a437afd9 100644 --- a/packages/@aws-cdk/assert/lib/synth-utils.ts +++ b/packages/@aws-cdk/assert/lib/synth-utils.ts @@ -65,7 +65,7 @@ export class SynthUtils { * Synthesizes the app in which a stack resides and returns the cloud assembly object. */ function synthesizeApp(stack: core.Stack, options: core.SynthesisOptions) { - const root = stack.construct.root; + const root = stack.node.root; if (!core.Stage.isStage(root)) { throw new Error('unexpected: all stacks must be part of a Stage or an App'); } diff --git a/packages/@aws-cdk/assets/test/test.staging.ts b/packages/@aws-cdk/assets/test/test.staging.ts index 2b155c75108af..a6841284e8731 100644 --- a/packages/@aws-cdk/assets/test/test.staging.ts +++ b/packages/@aws-cdk/assets/test/test.staging.ts @@ -23,7 +23,7 @@ export = { 'staging can be disabled through context'(test: Test) { // GIVEN const stack = new Stack(); - stack.construct.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); + stack.node.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); const sourcePath = path.join(__dirname, 'fs', 'fixtures', 'test1'); // WHEN diff --git a/packages/@aws-cdk/aws-amplify/lib/app.ts b/packages/@aws-cdk/aws-amplify/lib/app.ts index e18917afae9b2..1d41c0e07ede3 100644 --- a/packages/@aws-cdk/aws-amplify/lib/app.ts +++ b/packages/@aws-cdk/aws-amplify/lib/app.ts @@ -221,7 +221,7 @@ export class App extends Resource implements IApp, iam.IGrantable { description: props.description, environmentVariables: Lazy.anyValue({ produce: () => renderEnvironmentVariables(this.environmentVariables) }, { omitEmptyArray: true }), iamServiceRole: role.roleArn, - name: props.appName || this.construct.id, + name: props.appName || this.node.id, oauthToken: sourceCodeProviderOptions?.oauthToken?.toString(), repository: sourceCodeProviderOptions?.repository, }); diff --git a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts index 002a1e71aa157..f79d675af1e7f 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts @@ -12,7 +12,7 @@ export interface LambdaAuthorizerProps { /** * An optional human friendly name for the authorizer. Note that, this is not the primary identifier of the authorizer. * - * @default this.construct.uniqueId + * @default this.node.uniqueId */ readonly authorizerName?: string; @@ -96,7 +96,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer { */ protected setupPermissions() { if (!this.role) { - this.handler.addPermission(`${this.construct.uniqueId}:Permissions`, { + this.handler.addPermission(`${this.node.uniqueId}:Permissions`, { principal: new iam.ServicePrincipal('apigateway.amazonaws.com'), sourceArn: this.authorizerArn, }); @@ -120,7 +120,7 @@ abstract class LambdaAuthorizer extends Authorizer implements IAuthorizer { return Lazy.stringValue({ produce: () => { if (!this.restApiId) { - throw new Error(`Authorizer (${this.construct.path}) must be attached to a RestApi`); + throw new Error(`Authorizer (${this.node.path}) must be attached to a RestApi`); } return this.restApiId; }, @@ -167,7 +167,7 @@ export class TokenAuthorizer extends LambdaAuthorizer { const restApiId = this.lazyRestApiId(); const resource = new CfnAuthorizer(this, 'Resource', { - name: props.authorizerName ?? this.construct.uniqueId, + name: props.authorizerName ?? this.node.uniqueId, restApiId, type: 'TOKEN', authorizerUri: lambdaAuthorizerArn(props.handler), @@ -229,7 +229,7 @@ export class RequestAuthorizer extends LambdaAuthorizer { const restApiId = this.lazyRestApiId(); const resource = new CfnAuthorizer(this, 'Resource', { - name: props.authorizerName ?? this.construct.uniqueId, + name: props.authorizerName ?? this.node.uniqueId, restApiId, type: 'REQUEST', authorizerUri: lambdaAuthorizerArn(props.handler), diff --git a/packages/@aws-cdk/aws-apigateway/lib/deployment.ts b/packages/@aws-cdk/aws-apigateway/lib/deployment.ts index 799d6f9ccee72..404ba1855bd68 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/deployment.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/deployment.ts @@ -118,7 +118,7 @@ export class Deployment extends Resource { // and the `AWS::Lambda::Permission` resources (children under Method), // causing cyclic dependency errors. Hence, falling back to declaring // dependencies between the underlying CfnResources. - this.construct.addDependency(method.construct.defaultChild as CfnResource); + this.node.addDependency(method.node.defaultChild as CfnResource); } } @@ -150,7 +150,7 @@ class LatestDeploymentResource extends CfnDeployment { public addToLogicalId(data: unknown) { // if the construct is locked, it means we are already synthesizing and then // we can't modify the hash because we might have already calculated it. - if (this.construct.locked) { + if (this.node.locked) { throw new Error('Cannot modify the logical ID when the construct is locked'); } @@ -163,7 +163,7 @@ class LatestDeploymentResource extends CfnDeployment { if (this.api instanceof RestApi || this.api instanceof SpecRestApi) { // Ignore IRestApi that are imported // Add CfnRestApi to the logical id so a new deployment is triggered when any of its properties change. - const cfnRestApiCF = (this.api.construct.defaultChild as any)._toCloudFormation(); + const cfnRestApiCF = (this.api.node.defaultChild as any)._toCloudFormation(); hash.push(this.stack.resolve(cfnRestApiCF)); } diff --git a/packages/@aws-cdk/aws-apigateway/lib/domain-name.ts b/packages/@aws-cdk/aws-apigateway/lib/domain-name.ts index 5c85e3415354f..f44ebf953dcac 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/domain-name.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/domain-name.ts @@ -137,7 +137,7 @@ export class DomainName extends Resource implements IDomainName { */ public addBasePathMapping(targetApi: IRestApi, options: BasePathMappingOptions = { }) { const basePath = options.basePath || '/'; - const id = `Map:${basePath}=>${targetApi.construct.uniqueId}`; + const id = `Map:${basePath}=>${targetApi.node.uniqueId}`; return new BasePathMapping(this, id, { domainName: this, restApi: targetApi, diff --git a/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts b/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts index 35d02d7c15e27..62957167fa881 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts @@ -65,7 +65,7 @@ export class GatewayResponse extends Resource implements IGatewayResponse { statusCode: props.statusCode, }); - this.construct.defaultChild = resource; + this.node.defaultChild = resource; } private buildResponseParameters(responseHeaders?: { [key: string]: string }): { [key: string]: string } | undefined { diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts index 7d6ec4c2530ac..c6a8ec04863c7 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts @@ -56,7 +56,7 @@ export class LambdaIntegration extends AwsIntegration { const bindResult = super.bind(method); const principal = new iam.ServicePrincipal('apigateway.amazonaws.com'); - const desc = `${method.api.construct.uniqueId}.${method.httpMethod}.${method.resource.path.replace(/\//g, '.')}`; + const desc = `${method.api.node.uniqueId}.${method.httpMethod}.${method.resource.path.replace(/\//g, '.')}`; this.handler.addPermission(`ApiPermission.${desc}`, { principal, @@ -78,7 +78,7 @@ export class LambdaIntegration extends AwsIntegration { if (this.handler instanceof lambda.Function) { // if not imported, extract the name from the CFN layer to reach // the literal value if it is given (rather than a token) - functionName = (this.handler.construct.defaultChild as lambda.CfnFunction).functionName; + functionName = (this.handler.node.defaultChild as lambda.CfnFunction).functionName; } else { // imported, just take the function name. functionName = this.handler.functionName; diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index 586d0f2258a66..172eb77cd1877 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -221,7 +221,7 @@ export class Method extends Resource { const deployment = props.resource.api.latestDeployment; if (deployment) { - deployment.construct.addDependency(resource); + deployment.node.addDependency(resource); deployment.addToLogicalId({ method: { ...methodProps, diff --git a/packages/@aws-cdk/aws-apigateway/lib/model.ts b/packages/@aws-cdk/aws-apigateway/lib/model.ts index df0aa0b5d9718..088dee9b98750 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/model.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/model.ts @@ -178,7 +178,7 @@ export class Model extends Resource implements IModel { const deployment = (props.restApi instanceof RestApi) ? props.restApi.latestDeployment : undefined; if (deployment) { - deployment.construct.addDependency(resource); + deployment.node.addDependency(resource); deployment.addToLogicalId({ model: modelProps }); } } diff --git a/packages/@aws-cdk/aws-apigateway/lib/requestvalidator.ts b/packages/@aws-cdk/aws-apigateway/lib/requestvalidator.ts index b31155bf5c941..ce56903f79a0d 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/requestvalidator.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/requestvalidator.ts @@ -81,7 +81,7 @@ export class RequestValidator extends Resource implements IRequestValidator { const deployment = (props.restApi instanceof RestApi) ? props.restApi.latestDeployment : undefined; if (deployment) { - deployment.construct.addDependency(resource); + deployment.node.addDependency(resource); deployment.addToLogicalId({ validator: validatorProps }); } } diff --git a/packages/@aws-cdk/aws-apigateway/lib/resource.ts b/packages/@aws-cdk/aws-apigateway/lib/resource.ts index 003c4b0575ba5..102a17a5cdc27 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/resource.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/resource.ts @@ -410,7 +410,7 @@ export class Resource extends ResourceBase { const deployment = props.parent.api.latestDeployment; if (deployment) { - deployment.construct.addDependency(resource); + deployment.node.addDependency(resource); deployment.addToLogicalId({ resource: resourceProps }); } @@ -488,7 +488,7 @@ export class ProxyResource extends Resource { // the root so that empty paths are proxied as well. if (this.parentResource && this.parentResource.path === '/') { // skip if the root resource already has this method defined - if (!(this.parentResource.construct.tryFindChild(httpMethod) instanceof Method)) { + if (!(this.parentResource.node.tryFindChild(httpMethod) instanceof Method)) { this.parentResource.addMethod(httpMethod, integration, options); } } diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index 606bf536fbbf4..f027a2f7424be 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -401,7 +401,7 @@ export abstract class RestApiBase extends Resource implements IRestApi { cloudWatchRoleArn: role.roleArn, }); - resource.construct.addDependency(apiResource); + resource.node.addDependency(apiResource); } protected configureDeployment(props: RestApiOptions) { @@ -492,7 +492,7 @@ export class SpecRestApi extends RestApiBase { endpointConfiguration: this._configureEndpoints(props), parameters: props.parameters, }); - this.construct.defaultChild = resource; + this.node.defaultChild = resource; this.restApiId = resource.ref; this.restApiRootResourceId = resource.attrRootResourceId; this.root = new RootResource(this, {}, this.restApiRootResourceId); @@ -597,7 +597,7 @@ export class RestApi extends RestApiBase { cloneFrom: props.cloneFrom ? props.cloneFrom.restApiId : undefined, parameters: props.parameters, }); - this.construct.defaultChild = resource; + this.node.defaultChild = resource; this.restApiId = resource.ref; const cloudWatchRole = props.cloudWatchRole !== undefined ? props.cloudWatchRole : true; diff --git a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts index c25c744fa65ec..c6029c5840e4c 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts @@ -181,7 +181,7 @@ export class UsagePlan extends Resource { const prefix = 'UsagePlanKeyResource'; // Postfixing apikey id only from the 2nd child, to keep physicalIds of UsagePlanKey for existing CDK apps unmodifed. - const id = this.construct.tryFindChild(prefix) ? `${prefix}:${apiKey.construct.uniqueId}` : prefix; + const id = this.node.tryFindChild(prefix) ? `${prefix}:${apiKey.node.uniqueId}` : prefix; new CfnUsagePlanKey(this, id, { keyId: apiKey.keyId, diff --git a/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts b/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts index 2cc66b0f8885c..81f6f843b97df 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts @@ -65,7 +65,7 @@ export class VpcLink extends Resource implements IVpcLink { constructor(scope: Construct, id: string, props: VpcLinkProps = {}) { super(scope, id, { physicalName: props.vpcLinkName || - Lazy.stringValue({ produce: () => this.construct.uniqueId }), + Lazy.stringValue({ produce: () => this.node.uniqueId }), }); const cfnResource = new CfnVpcLink(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts index 60017e092f340..bea2be6c5b05f 100644 --- a/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts +++ b/packages/@aws-cdk/aws-apigateway/test/integ.restapi-import.lit.ts @@ -116,7 +116,7 @@ class DeployStack extends NestedStack { const deployment = new Deployment(this, 'Deployment', { api: RestApi.fromRestApiId(this, 'RestApi', props.restApiId), }); - (props.methods ?? []).forEach((method) => deployment.construct.addDependency(method)); + (props.methods ?? []).forEach((method) => deployment.node.addDependency(method)); new Stage(this, 'Stage', { deployment }); } } diff --git a/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts b/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts index ebacaac1973c2..0f5ce4a37732d 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts @@ -178,7 +178,7 @@ export = { const dep = new CfnResource(stack, 'MyResource', { type: 'foo' }); // WHEN - deployment.construct.addDependency(dep); + deployment.node.addDependency(dep); expect(stack).to(haveResource('AWS::ApiGateway::Deployment', { DependsOn: [ diff --git a/packages/@aws-cdk/aws-apigateway/test/test.method.ts b/packages/@aws-cdk/aws-apigateway/test/test.method.ts index b4a94b20bf44c..85111b4636882 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.method.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.method.ts @@ -474,7 +474,7 @@ export = { expect(stack).to(haveResource('AWS::ApiGateway::Method', { HttpMethod: 'GET', RequestModels: { - 'application/json': { Ref: stack.getLogicalId(model.construct.findChild('Resource') as cdk.CfnElement) }, + 'application/json': { Ref: stack.getLogicalId(model.node.findChild('Resource') as cdk.CfnElement) }, }, })); @@ -539,7 +539,7 @@ export = { ResponseModels: { 'application/json': 'Empty', 'text/plain': 'Error', - 'text/html': { Ref: stack.getLogicalId(htmlModel.construct.findChild('Resource') as cdk.CfnElement) }, + 'text/html': { Ref: stack.getLogicalId(htmlModel.node.findChild('Resource') as cdk.CfnElement) }, }, }, ], @@ -568,10 +568,10 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::Method', { - RequestValidatorId: { Ref: stack.getLogicalId(validator.construct.findChild('Resource') as cdk.CfnElement) }, + RequestValidatorId: { Ref: stack.getLogicalId(validator.node.findChild('Resource') as cdk.CfnElement) }, })); expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, ValidateRequestBody: true, ValidateRequestParameters: false, })); diff --git a/packages/@aws-cdk/aws-apigateway/test/test.model.ts b/packages/@aws-cdk/aws-apigateway/test/test.model.ts index a6f4e5fa393fd..9f0907b1e66f2 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.model.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.model.ts @@ -26,7 +26,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::Model', { - RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, Schema: { $schema: 'http://json-schema.org/draft-04/schema#', title: 'test', @@ -61,7 +61,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::Model', { - RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, Schema: { $schema: 'http://json-schema.org/draft-04/schema#', title: 'test', diff --git a/packages/@aws-cdk/aws-apigateway/test/test.requestvalidator.ts b/packages/@aws-cdk/aws-apigateway/test/test.requestvalidator.ts index f7b9e89d65632..b264f85c0733c 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.requestvalidator.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.requestvalidator.ts @@ -22,7 +22,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, ValidateRequestBody: true, ValidateRequestParameters: false, })); @@ -49,7 +49,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as cdk.CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as cdk.CfnElement) }, Name: 'my-model', ValidateRequestBody: false, ValidateRequestParameters: true, diff --git a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts index 4ae50a9910065..9736dc2e188b5 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts @@ -103,7 +103,7 @@ export = { 'defaultChild is set correctly'(test: Test) { const stack = new Stack(); const api = new apigw.RestApi(stack, 'my-api'); - test.ok(api.construct.defaultChild instanceof apigw.CfnRestApi); + test.ok(api.node.defaultChild instanceof apigw.CfnRestApi); test.done(); }, @@ -570,7 +570,7 @@ export = { const resource = new CfnResource(stack, 'DependsOnRestApi', { type: 'My::Resource' }); // WHEN - resource.construct.addDependency(api); + resource.node.addDependency(api); // THEN expect(stack).to(haveResource('My::Resource', { @@ -713,7 +713,7 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::Model', { - RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as CfnElement) }, Schema: { $schema: 'http://json-schema.org/draft-04/schema#', title: 'test', @@ -745,14 +745,14 @@ export = { // THEN expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as CfnElement) }, Name: 'Parameters', ValidateRequestBody: false, ValidateRequestParameters: true, })); expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { - RestApiId: { Ref: stack.getLogicalId(api.construct.findChild('Resource') as CfnElement) }, + RestApiId: { Ref: stack.getLogicalId(api.node.findChild('Resource') as CfnElement) }, Name: 'Body', ValidateRequestBody: true, ValidateRequestParameters: false, diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api-mapping.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api-mapping.ts index cc35eeb466ace..17461f258b288 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api-mapping.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api-mapping.ts @@ -93,12 +93,12 @@ export class HttpApiMapping extends Resource implements IApiMapping { // ensure the dependency on the provided stage if (props.stage) { - this.construct.addDependency(props.stage); + this.node.addDependency(props.stage); } // if stage not specified, we ensure the default stage is ready before we create the api mapping if (!props.stage?.stageName && props.api.defaultStage) { - this.construct.addDependency(props.api.defaultStage!); + this.node.addDependency(props.api.defaultStage!); } this.apiMappingId = resource.ref; diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index 56931abf0b37e..d868b25f9eea1 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -191,7 +191,7 @@ export class HttpApi extends Resource implements IHttpApi { // to ensure the domain is ready before creating the default stage if(props?.defaultDomainMapping) { - this.defaultStage.construct.addDependency(props.defaultDomainMapping.domainName); + this.defaultStage.node.addDependency(props.defaultDomainMapping.domainName); } } diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integrations/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integrations/lambda.ts index fe656e0a03947..30973a10b2ca0 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/integrations/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/integrations/lambda.ts @@ -30,7 +30,7 @@ export class LambdaProxyIntegration implements IHttpRouteIntegration { public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig { const route = options.route; - this.props.handler.addPermission(`${route.construct.uniqueId}-Permission`, { + this.props.handler.addPermission(`${route.node.uniqueId}-Permission`, { scope: options.scope, principal: new ServicePrincipal('apigateway.amazonaws.com'), sourceArn: Stack.of(route).formatArn({ diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts index 09be9668a1267..2f65902a6aaee 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/route.ts @@ -124,7 +124,7 @@ export class HttpRoute extends Resource implements IHttpRoute { route: this, scope: this, }); - integration = new HttpIntegration(this, `${this.construct.id}-Integration`, { + integration = new HttpIntegration(this, `${this.node.id}-Integration`, { httpApi: props.httpApi, integrationType: config.type, integrationUri: config.uri, diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts index 9a171681b0715..a9e7de3ce9af2 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts @@ -103,7 +103,7 @@ export class HttpStage extends Resource implements IStage { apiMappingKey: props.domainMapping.mappingKey, }); // ensure the dependency - this.construct.addDependency(props.domainMapping.domainName); + this.node.addDependency(props.domainMapping.domainName); } } diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts index 92f639a0c45ad..fac49b523e8ea 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts @@ -81,7 +81,7 @@ export class StepScalingAction extends cdk.Construct { // properties, or the ScalingTargetId property, but not both. // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationautoscaling-scalingpolicy.html const resource = new CfnScalingPolicy(this, 'Resource', { - policyName: props.policyName || this.construct.uniqueId, + policyName: props.policyName || this.node.uniqueId, policyType: 'StepScaling', scalingTargetId: props.scalingTarget.scalableTargetId, stepScalingPolicyConfiguration: { diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts index 498de4e70b7ef..8a314f0b1ac22 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts @@ -132,7 +132,7 @@ export class TargetTrackingScalingPolicy extends cdk.Construct { super(scope, id); const resource = new CfnScalingPolicy(this, 'Resource', { - policyName: props.policyName || this.construct.uniqueId, + policyName: props.policyName || this.node.uniqueId, policyType: 'TargetTrackingScaling', scalingTargetId: props.scalingTarget.scalableTargetId, targetTrackingScalingPolicyConfiguration: { diff --git a/packages/@aws-cdk/aws-appmesh/lib/mesh.ts b/packages/@aws-cdk/aws-appmesh/lib/mesh.ts index 6479296b4ee33..8e39cb4657d1e 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/mesh.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/mesh.ts @@ -170,7 +170,7 @@ export class Mesh extends MeshBase { constructor(scope: cdk.Construct, id: string, props: MeshProps = {}) { super(scope, id, { - physicalName: props.meshName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), + physicalName: props.meshName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), }); const mesh = new CfnMesh(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-appmesh/lib/route.ts b/packages/@aws-cdk/aws-appmesh/lib/route.ts index 01433c1d7f55f..8534ad70dcf14 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/route.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/route.ts @@ -145,7 +145,7 @@ export class Route extends cdk.Resource implements IRoute { constructor(scope: cdk.Construct, id: string, props: RouteProps) { super(scope, id, { - physicalName: props.routeName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), + physicalName: props.routeName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), }); this.virtualRouter = props.virtualRouter; diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts index 1b406878dc896..f7a2548a48e7b 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts @@ -245,7 +245,7 @@ export class VirtualNode extends VirtualNodeBase { constructor(scope: cdk.Construct, id: string, props: VirtualNodeProps) { super(scope, id, { - physicalName: props.virtualNodeName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), + physicalName: props.virtualNodeName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), }); this.mesh = props.mesh; diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts index 0249ace5e06f5..3403b47378c5c 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-router.ts @@ -145,7 +145,7 @@ export class VirtualRouter extends VirtualRouterBase { constructor(scope: cdk.Construct, id: string, props: VirtualRouterProps) { super(scope, id, { - physicalName: props.virtualRouterName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), + physicalName: props.virtualRouterName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), }); this.mesh = props.mesh; diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts index 1ef3ef41eb788..9cc678ec266a9 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-service.ts @@ -106,7 +106,7 @@ export class VirtualService extends cdk.Resource implements IVirtualService { constructor(scope: cdk.Construct, id: string, props: VirtualServiceProps) { super(scope, id, { - physicalName: props.virtualServiceName || cdk.Lazy.stringValue({ produce: () => this.construct.uniqueId }), + physicalName: props.virtualServiceName || cdk.Lazy.stringValue({ produce: () => this.node.uniqueId }), }); if (props.virtualNode && props.virtualRouter) { diff --git a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts index e19f7db7fd83a..07aa86ff45306 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -471,7 +471,7 @@ abstract class AutoScalingGroupBase extends Resource implements IAutoScalingGrou ...props, }); - policy.construct.addDependency(this.albTargetGroup.loadBalancerAttached); + policy.node.addDependency(this.albTargetGroup.loadBalancerAttached); return policy; } @@ -595,7 +595,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements }); this.connections = new ec2.Connections({ securityGroups: [this.securityGroup] }); this.securityGroups.push(this.securityGroup); - this.construct.applyAspect(new Tag(NAME_TAG, this.construct.path)); + this.node.applyAspect(new Tag(NAME_TAG, this.node.path)); this.role = props.role || new iam.Role(this, 'InstanceRole', { roleName: PhysicalName.GENERATE_IF_NEEDED, @@ -632,7 +632,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements synthesizeBlockDeviceMappings(this, props.blockDevices) : undefined), }); - launchConfig.construct.addDependency(this.role); + launchConfig.node.addDependency(this.role); // desiredCapacity just reflects what the user has supplied. const desiredCapacity = props.desiredCapacity; @@ -659,7 +659,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements }); if (desiredCapacity !== undefined) { - this.construct.addWarning('desiredCapacity has been configured. Be aware this will reset the size of your AutoScalingGroup on every deployment. See https://github.com/aws/aws-cdk/issues/5215'); + this.node.addWarning('desiredCapacity has been configured. Be aware this will reset the size of your AutoScalingGroup on every deployment. See https://github.com/aws/aws-cdk/issues/5215'); } this.maxInstanceLifetime = props.maxInstanceLifetime; @@ -715,7 +715,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements resource: 'autoScalingGroup:*:autoScalingGroupName', resourceName: this.autoScalingGroupName, }); - this.construct.defaultChild = this.autoScalingGroup; + this.node.defaultChild = this.autoScalingGroup; this.applyUpdatePolicies(props); @@ -1259,7 +1259,7 @@ function synthesizeBlockDeviceMappings(construct: Construct, blockDevices: Block throw new Error('iops property is required with volumeType: EbsDeviceVolumeType.IO1'); } } else if (volumeType !== EbsDeviceVolumeType.IO1) { - construct.construct.addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + construct.node.addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); } } diff --git a/packages/@aws-cdk/aws-autoscaling/lib/lifecycle-hook.ts b/packages/@aws-cdk/aws-autoscaling/lib/lifecycle-hook.ts index 841e5bc5b46c8..9c6f1d7f15322 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/lifecycle-hook.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/lifecycle-hook.ts @@ -116,7 +116,7 @@ export class LifecycleHook extends Resource implements ILifecycleHook { // A LifecycleHook resource is going to do a permissions test upon creation, // so we have to make sure the role has full permissions before creating the // lifecycle hook. - resource.construct.addDependency(this.role); + resource.node.addDependency(this.role); this.lifecycleHookName = resource.ref; } diff --git a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts index d992fd8ba602f..52242e44bda29 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts @@ -511,8 +511,8 @@ nodeunitShim({ pauseTime: cdk.Duration.seconds(345), }, }); - asg.construct.applyAspect(new cdk.Tag('superfood', 'acai')); - asg.construct.applyAspect(new cdk.Tag('notsuper', 'caramel', { applyToLaunchedInstances: false })); + asg.node.applyAspect(new cdk.Tag('superfood', 'acai')); + asg.node.applyAspect(new cdk.Tag('notsuper', 'caramel', { applyToLaunchedInstances: false })); // THEN expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup', { @@ -713,7 +713,7 @@ nodeunitShim({ }); // THEN - test.ok(asg.construct.defaultChild instanceof autoscaling.CfnAutoScalingGroup); + test.ok(asg.node.defaultChild instanceof autoscaling.CfnAutoScalingGroup); test.done(); }, @@ -958,8 +958,8 @@ nodeunitShim({ }); // THEN - test.deepEqual(asg.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(asg.construct.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + test.deepEqual(asg.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(asg.node.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); test.done(); }, @@ -985,8 +985,8 @@ nodeunitShim({ }); // THEN - test.deepEqual(asg.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(asg.construct.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + test.deepEqual(asg.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(asg.node.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); test.done(); }, diff --git a/packages/@aws-cdk/aws-backup/lib/plan.ts b/packages/@aws-cdk/aws-backup/lib/plan.ts index c9f9cc6d65c70..99301fde7bde9 100644 --- a/packages/@aws-cdk/aws-backup/lib/plan.ts +++ b/packages/@aws-cdk/aws-backup/lib/plan.ts @@ -161,7 +161,7 @@ export class BackupPlan extends Resource implements IBackupPlan { deleteAfterDays: rule.props.deleteAfter?.toDays(), moveToColdStorageAfterDays: rule.props.moveToColdStorageAfter?.toDays(), }, - ruleName: rule.props.ruleName ?? `${this.construct.id}Rule${this.rules.length}`, + ruleName: rule.props.ruleName ?? `${this.node.id}Rule${this.rules.length}`, scheduleExpression: rule.props.scheduleExpression?.expressionString, startWindowMinutes: rule.props.startWindow?.toMinutes(), targetBackupVault: vault.backupVaultName, diff --git a/packages/@aws-cdk/aws-backup/lib/selection.ts b/packages/@aws-cdk/aws-backup/lib/selection.ts index 9e6d6bd846565..4e1ba54b472cb 100644 --- a/packages/@aws-cdk/aws-backup/lib/selection.ts +++ b/packages/@aws-cdk/aws-backup/lib/selection.ts @@ -94,7 +94,7 @@ export class BackupSelection extends Resource implements iam.IGrantable { backupPlanId: props.backupPlan.backupPlanId, backupSelection: { iamRoleArn: role.roleArn, - selectionName: props.backupSelectionName || this.construct.id, + selectionName: props.backupSelectionName || this.node.id, listOfTags: Lazy.anyValue({ produce: () => this.listOfTags, }, { omitEmptyArray: true }), @@ -126,7 +126,7 @@ export class BackupSelection extends Resource implements iam.IGrantable { } if (resource.construct) { - resource.construct.construct.applyAspect(this.backupableResourcesCollector); + resource.construct.node.applyAspect(this.backupableResourcesCollector); // Cannot push `this.backupableResourcesCollector.resources` to // `this.resources` here because it has not been evaluated yet. // Will be concatenated to `this.resources` in a `Lazy.listValue` diff --git a/packages/@aws-cdk/aws-backup/lib/vault.ts b/packages/@aws-cdk/aws-backup/lib/vault.ts index dbbf01869871b..e9f85d8b160b1 100644 --- a/packages/@aws-cdk/aws-backup/lib/vault.ts +++ b/packages/@aws-cdk/aws-backup/lib/vault.ts @@ -160,7 +160,7 @@ export class BackupVault extends Resource implements IBackupVault { private uniqueVaultName() { // Max length of 50 chars, get the last 50 chars - const id = this.construct.uniqueId; + const id = this.node.uniqueId; return id.substring(Math.max(id.length - 50, 0), id.length); } } diff --git a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts index 3d9112d22a09d..5d18ae0ca635e 100644 --- a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts +++ b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts @@ -386,7 +386,7 @@ export class ComputeEnvironment extends Resource implements IComputeEnvironment }); if (props.computeResources && props.computeResources.vpc) { - this.construct.addDependency(props.computeResources.vpc); + this.node.addDependency(props.computeResources.vpc); } this.computeEnvironmentArn = this.getResourceArnAttribute(computeEnvironment.ref, { diff --git a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts index bb25f2de40165..36258615fbf8e 100644 --- a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts +++ b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts @@ -237,10 +237,10 @@ describe('Batch Compute Evironment', () => { ], Subnets: [ { - Ref: `${vpc.construct.uniqueId}PrivateSubnet1Subnet865FB50A`, + Ref: `${vpc.node.uniqueId}PrivateSubnet1Subnet865FB50A`, }, { - Ref: `${vpc.construct.uniqueId}PrivateSubnet2Subnet23D3396F`, + Ref: `${vpc.node.uniqueId}PrivateSubnet2Subnet23D3396F`, }, ], Tags: { diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/util.ts b/packages/@aws-cdk/aws-certificatemanager/lib/util.ts index 743b1e4faf8b7..219bac1fd6a80 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lib/util.ts +++ b/packages/@aws-cdk/aws-certificatemanager/lib/util.ts @@ -28,7 +28,7 @@ export function getCertificateRegion(cert: ICertificate): string | undefined { const { certificateArn, stack } = cert; if (isDnsValidatedCertificate(cert)) { - const requestResource = cert.construct.findChild('CertificateRequestorResource').construct.defaultChild; + const requestResource = cert.node.findChild('CertificateRequestorResource').node.defaultChild; // @ts-ignore const { _cfnProperties: properties } = requestResource; diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts b/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts index 95cca4fa0efc2..0b39949203fe0 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts @@ -335,7 +335,7 @@ export = { function matrixForResourceDependencyTest(testFunction: (test: Test, addDep: (source: CfnResource, target: CfnResource) => void) => void) { return { 'construct dependency'(test: Test) { - testFunction(test, (source, target) => source.construct.addDependency(target)); + testFunction(test, (source, target) => source.node.addDependency(target)); }, 'resource dependency'(test: Test) { testFunction(test, (source, target) => source.addDependsOn(target)); diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts index 94f42a6ecef7f..4eedbf0e75c4c 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts @@ -62,7 +62,7 @@ export = { const assembly = app.synth(); // THEN - const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, `${nested.construct.uniqueId}.nested.template.json`), 'utf-8')); + const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, `${nested.node.uniqueId}.nested.template.json`), 'utf-8')); test.deepEqual(template, { Resources: { ResourceInNestedStack: { @@ -847,7 +847,7 @@ export = { const resource = new CfnResource(nested, 'resource', { type: 'foo' }); // WHEN - resource.construct.addMetadata('foo', 'bar'); + resource.node.addMetadata('foo', 'bar'); // THEN: the first non-nested stack records the assembly metadata const asm = app.synth(); diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index 2598c0cb10aa0..81cb0e7470ec4 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -196,7 +196,7 @@ export class Distribution extends Resource implements IDistribution { } else { const originIndex = this.boundOrigins.length + 1; const scope = new Construct(this, `Origin${originIndex}`); - const originId = scope.construct.uniqueId; + const originId = scope.node.uniqueId; const originBindConfig = origin.bind(scope, { originId }); this.boundOrigins.push({ origin, originId, ...originBindConfig }); if (originBindConfig.failoverConfig) { @@ -223,7 +223,7 @@ export class Distribution extends Resource implements IDistribution { quantity: statusCodes.length, }, }, - id: new Construct(this, `OriginGroup${groupIndex}`).construct.uniqueId, + id: new Construct(this, `OriginGroup${groupIndex}`).node.uniqueId, members: { items: [ { originId }, diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index e93ddecaf1d79..b2fc472adfd46 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -924,7 +924,7 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu } const distribution = new CfnDistribution(this, 'CFDistribution', { distributionConfig }); - this.construct.defaultChild = distribution; + this.node.defaultChild = distribution; this.domainName = distribution.attrDomainName; this.distributionDomainName = distribution.attrDomainName; this.distributionId = distribution.ref; diff --git a/packages/@aws-cdk/aws-cloudfront/test/web_distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web_distribution.test.ts index 5cf6751f50f87..c8b2fb322995f 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web_distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web_distribution.test.ts @@ -491,7 +491,7 @@ nodeunitShim({ ], }); - test.ok(distribution.construct.defaultChild instanceof CfnDistribution); + test.ok(distribution.node.defaultChild instanceof CfnDistribution); test.done(); }, diff --git a/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts b/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts index 217b578b8244b..e41a50b1cb66d 100644 --- a/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts +++ b/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts @@ -295,14 +295,14 @@ export class Trail extends Resource { // Add a dependency on the bucket policy being updated, CloudTrail will test this upon creation. if (this.s3bucket.policy) { - trail.construct.addDependency(this.s3bucket.policy); + trail.node.addDependency(this.s3bucket.policy); } // If props.sendToCloudWatchLogs is set to true then the trail needs to depend on the created logsRole // so that it can create the log stream for the log group. This ensures the logsRole is created and propagated // before the trail tries to create the log stream. if (logsRole !== undefined) { - trail.construct.addDependency(logsRole); + trail.node.addDependency(logsRole); } } diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/composite-alarm.ts b/packages/@aws-cdk/aws-cloudwatch/lib/composite-alarm.ts index b204d776dfb1c..4d20f5f3f1300 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/composite-alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/composite-alarm.ts @@ -119,7 +119,7 @@ export class CompositeAlarm extends AlarmBase { } private generateUniqueId(): string { - const name = this.construct.uniqueId; + const name = this.node.uniqueId; if (name.length > 240) { return name.substring(0, 120) + name.substring(name.length - 120); } diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index c5f231c443d8e..d4f349431b544 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -1007,7 +1007,7 @@ export class Project extends ProjectBase { } else { const securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, - description: 'Automatic generated security group for CodeBuild ' + this.construct.uniqueId, + description: 'Automatic generated security group for CodeBuild ' + this.node.uniqueId, allowAllOutbound: props.allowAllOutbound, }); securityGroups = [securityGroup]; @@ -1060,7 +1060,7 @@ export class Project extends ProjectBase { // add an explicit dependency between the EC2 Policy and this Project - // otherwise, creating the Project fails, as it requires these permissions // to be already attached to the Project's Role - project.construct.addDependency(policy); + project.node.addDependency(policy); } private validateCodePipelineSettings(artifacts: IArtifacts) { diff --git a/packages/@aws-cdk/aws-codecommit/lib/repository.ts b/packages/@aws-cdk/aws-codecommit/lib/repository.ts index 1c1d569d78ec8..7dfb132138936 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/repository.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/repository.ts @@ -367,7 +367,7 @@ export class Repository extends RepositoryBase { let name = options && options.name; if (!name) { - name = this.construct.path + '/' + arn; + name = this.node.path + '/' + arn; } if (this.triggers.find(prop => prop.name === name)) { diff --git a/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts index 154a644ce5a41..074667136417f 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts @@ -189,7 +189,7 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy this.addPostHook(props.postHook); } - (props.alias.construct.defaultChild as lambda.CfnAlias).cfnOptions.updatePolicy = { + (props.alias.node.defaultChild as lambda.CfnAlias).cfnOptions.updatePolicy = { codeDeployLambdaAliasUpdate: { applicationName: this.application.applicationName, deploymentGroupName: resource.ref, diff --git a/packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts b/packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts index 30308c991b094..f4d356e093204 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts +++ b/packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts @@ -170,7 +170,7 @@ export class ProfilingGroup extends ProfilingGroupBase { } private generateUniqueId(): string { - const name = this.construct.uniqueId; + const name = this.node.uniqueId; if (name.length > 240) { return name.substring(0, 120) + name.substring(name.length - 120); } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts index d59ece2b1d2e5..1982b0b8336bf 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts @@ -270,7 +270,7 @@ abstract class CloudFormationDeployAction extends CloudFormationAction { // pass role is not allowed for cross-account access - so, // create the deployment Role in the other account! this._deploymentRole = new iam.Role(roleStack, - `${stage.pipeline.construct.uniqueId}-${stage.stageName}-${this.actionProperties.actionName}-DeploymentRole`, { + `${stage.pipeline.node.uniqueId}-${stage.stageName}-${this.actionProperties.actionName}-DeploymentRole`, { assumedBy: new iam.ServicePrincipal('cloudformation.amazonaws.com'), roleName: cdk.PhysicalName.GENERATE_IF_NEEDED, }); @@ -500,7 +500,7 @@ class SingletonPolicy extends cdk.Construct implements iam.IGrantable { * @returns the SingletonPolicy for this role. */ public static forRole(role: iam.IRole): SingletonPolicy { - const found = role.construct.tryFindChild(SingletonPolicy.UUID); + const found = role.node.tryFindChild(SingletonPolicy.UUID); return (found as SingletonPolicy) || new SingletonPolicy(role); } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts index ea5735708e842..2fa7a67b29b93 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts @@ -123,7 +123,7 @@ export class CodeCommitSourceAction extends Action { this.props.trigger === CodeCommitTrigger.EVENTS; if (createEvent) { const branchIdDisambiguator = this.branch === 'master' ? '' : `-${this.branch}-`; - this.props.repository.onCommit(`${stage.pipeline.construct.uniqueId}${branchIdDisambiguator}EventRule`, { + this.props.repository.onCommit(`${stage.pipeline.node.uniqueId}${branchIdDisambiguator}EventRule`, { target: new targets.CodePipeline(stage.pipeline), branches: [this.branch], }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts index 23f6158e8ef1b..b9261cf34d878 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts @@ -89,7 +89,7 @@ export class EcrSourceAction extends Action { resources: [this.props.repository.repositoryArn], })); - this.props.repository.onCloudTrailImagePushed(stage.pipeline.construct.uniqueId + 'SourceEventRule', { + this.props.repository.onCloudTrailImagePushed(stage.pipeline.node.uniqueId + 'SourceEventRule', { target: new targets.CodePipeline(stage.pipeline), imageTag: this.props.imageTag, }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts index 9891f79b7125e..7608aa3d94ae0 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts @@ -110,8 +110,8 @@ export class S3SourceAction extends Action { protected bound(_scope: Construct, stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { if (this.props.trigger === S3Trigger.EVENTS) { - const id = stage.pipeline.construct.uniqueId + 'SourceEventRule' + this.props.bucketKey; - if (this.props.bucket.construct.tryFindChild(id)) { + const id = stage.pipeline.node.uniqueId + 'SourceEventRule' + this.props.bucketKey; + if (this.props.bucket.node.tryFindChild(id)) { // this means a duplicate path for the same bucket - error out throw new Error(`S3 source action with path '${this.props.bucketKey}' is already present in the pipeline for this source bucket`); } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts index c6f8f9c6085fe..122add214cc3a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts @@ -659,7 +659,7 @@ export = { }, })); - const otherStack = app.construct.findChild('cross-account-support-stack-123456789012') as cdk.Stack; + const otherStack = app.node.findChild('cross-account-support-stack-123456789012') as cdk.Stack; expect(otherStack).to(haveResourceLike('AWS::IAM::Role', { 'RoleName': 'pipelinestack-support-123loycfnactionrole56af64af3590f311bc50', })); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts index 0e284546218b7..6a7001630b3c5 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts @@ -653,8 +653,8 @@ export = { test.notEqual(usEast1Support, undefined); test.equal(usEast1Support.stack.region, 'us-east-1'); test.equal(usEast1Support.stack.account, pipelineAccount); - test.ok(usEast1Support.stack.construct.id.indexOf('us-east-1') !== -1, - `expected '${usEast1Support.stack.construct.id}' to contain 'us-east-1'`); + test.ok(usEast1Support.stack.node.id.indexOf('us-east-1') !== -1, + `expected '${usEast1Support.stack.node.id}' to contain 'us-east-1'`); test.done(); }, diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 960fe23e5496e..b498c20945f83 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -262,7 +262,7 @@ export class Pipeline extends PipelineBase { }); // this will produce a DependsOn for both the role and the policy resources. - codePipeline.construct.addDependency(this.role); + codePipeline.node.addDependency(this.role); this.artifactBucket.grantReadWrite(this.role); this.pipelineName = this.getResourceNameAttribute(codePipeline.ref); @@ -460,7 +460,7 @@ export class Pipeline extends PipelineBase { if (otherStack) { // check if the stack doesn't have this magic construct already const id = `CrossRegionReplicationSupport-d823f1d8-a990-4e5c-be18-4ac698532e65-${actionRegion}`; - let crossRegionSupportConstruct = otherStack.construct.tryFindChild(id) as CrossRegionSupportConstruct; + let crossRegionSupportConstruct = otherStack.node.tryFindChild(id) as CrossRegionSupportConstruct; if (!crossRegionSupportConstruct) { crossRegionSupportConstruct = new CrossRegionSupportConstruct(otherStack, id); } @@ -480,7 +480,7 @@ export class Pipeline extends PipelineBase { const app = this.requireApp(); const supportStackId = `cross-region-stack-${pipelineAccount}:${actionRegion}`; - let supportStack = app.construct.tryFindChild(supportStackId) as CrossRegionSupportStack; + let supportStack = app.node.tryFindChild(supportStackId) as CrossRegionSupportStack; if (!supportStack) { supportStack = new CrossRegionSupportStack(app, supportStackId, { pipelineStackName: pipelineStack.stackName, @@ -516,7 +516,7 @@ export class Pipeline extends PipelineBase { private generateNameForDefaultBucketKeyAlias(): string { const prefix = 'alias/codepipeline-'; const maxAliasLength = 256; - const uniqueId = this.construct.uniqueId; + const uniqueId = this.node.uniqueId; // take the last 256 - (prefix length) characters of uniqueId const startIndex = Math.max(0, uniqueId.length - (maxAliasLength - prefix.length)); return prefix + uniqueId.substring(startIndex).toLowerCase(); @@ -598,7 +598,7 @@ export class Pipeline extends PipelineBase { // generate a role in the other stack, that the Pipeline will assume for executing this action const ret = new iam.Role(otherAccountStack, - `${this.construct.uniqueId}-${stage.stageName}-${action.actionProperties.actionName}-ActionRole`, { + `${this.node.uniqueId}-${stage.stageName}-${action.actionProperties.actionName}-ActionRole`, { assumedBy: new iam.AccountPrincipal(pipelineStack.account), roleName: PhysicalName.GENERATE_IF_NEEDED, }); @@ -652,7 +652,7 @@ export class Pipeline extends PipelineBase { if (!targetAccountStack) { const stackId = `cross-account-support-stack-${targetAccount}`; const app = this.requireApp(); - targetAccountStack = app.construct.tryFindChild(stackId) as Stack; + targetAccountStack = app.node.tryFindChild(stackId) as Stack; if (!targetAccountStack) { targetAccountStack = new Stack(app, stackId, { stackName: `${pipelineStack.stackName}-support-${targetAccount}`, @@ -858,7 +858,7 @@ export class Pipeline extends PipelineBase { } private requireApp(): App { - const app = this.construct.root; + const app = this.node.root; if (!app || !App.isApp(app)) { throw new Error('Pipeline stack which uses cross-environment actions must be part of a CDK app'); } diff --git a/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts index 5bc9a52fcef49..32f3604191e6a 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts @@ -302,7 +302,7 @@ export = { const app = new cdk.App({ treeMetadata: false, // we can't set the context otherwise, because App will have a child }); - app.construct.setContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT, true); + app.node.setContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT, true); const pipelineStack = new cdk.Stack(app, 'PipelineStack', { env: { region: 'us-west-2', account: '123456789012' }, diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index ddbc7da3992d3..80a65675a0856 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -865,7 +865,7 @@ export class UserPool extends UserPoolBase { return undefined; } - const smsRoleExternalId = this.construct.uniqueId.substr(0, 1223); // sts:ExternalId max length of 1224 + const smsRoleExternalId = this.node.uniqueId.substr(0, 1223); // sts:ExternalId max length of 1224 const smsRole = props.smsRole ?? new Role(this, 'smsRole', { assumedBy: new ServicePrincipal('cognito-idp.amazonaws.com', { conditions: { diff --git a/packages/@aws-cdk/aws-config/lib/rule.ts b/packages/@aws-cdk/aws-config/lib/rule.ts index 2526f9ddd1981..12dd86b8ab1bd 100644 --- a/packages/@aws-cdk/aws-config/lib/rule.ts +++ b/packages/@aws-cdk/aws-config/lib/rule.ts @@ -357,7 +357,7 @@ export class CustomRule extends RuleNew { } // The lambda permission must be created before the rule - this.construct.addDependency(props.lambdaFunction); + this.node.addDependency(props.lambdaFunction); const rule = new CfnConfigRule(this, 'Resource', { configRuleName: this.physicalName, diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts index c8bb03243eab2..339ef8f0b51a0 100644 --- a/packages/@aws-cdk/aws-docdb/lib/cluster.ts +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -303,7 +303,7 @@ export class DatabaseCluster extends DatabaseClusterBase { }); // HACK: Use an escape-hatch to apply a consistent removal policy to the // security group so we don't get errors when trying to delete the stack - (securityGroup.construct.defaultChild as CfnResource).applyRemovalPolicy(props.removalPolicy, { + (securityGroup.node.defaultChild as CfnResource).applyRemovalPolicy(props.removalPolicy, { applyToUpdateReplacePolicy: true, }); } @@ -389,7 +389,7 @@ export class DatabaseCluster extends DatabaseClusterBase { // We must have a dependency on the NAT gateway provider here to create // things in the right order. - instance.construct.addDependency(internetConnectivityEstablished); + instance.node.addDependency(internetConnectivityEstablished); this.instanceIdentifiers.push(instance.ref); this.instanceEndpoints.push(new Endpoint(instance.attrEndpoint, port)); @@ -413,7 +413,7 @@ export class DatabaseCluster extends DatabaseClusterBase { } const id = 'RotationSingleUser'; - const existing = this.construct.tryFindChild(id); + const existing = this.node.tryFindChild(id); if (existing) { throw new Error('A single user rotation was already added to this cluster.'); } diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index 581716d149ef9..957ea0bd40a85 100644 --- a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -775,6 +775,6 @@ describe('DatabaseCluster', () => { function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' }}); - stack.construct.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + stack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); return stack; } diff --git a/packages/@aws-cdk/aws-docdb/test/instance.test.ts b/packages/@aws-cdk/aws-docdb/test/instance.test.ts index a4b3d849073f0..197e2e296fd8d 100644 --- a/packages/@aws-cdk/aws-docdb/test/instance.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/instance.test.ts @@ -173,7 +173,7 @@ class TestStack extends cdk.Stack { constructor(scope?: cdk.Construct, id?: string, props: cdk.StackProps = {}) { super(scope, id, props); - this.construct.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + this.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); this.vpc = new ec2.Vpc(this, 'VPC'); this.cluster = new DatabaseCluster(this, 'Database', { diff --git a/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts b/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts index 03cad4f4ed397..d72ff1f42c176 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/lib/aws-dynamodb-global.ts @@ -40,7 +40,7 @@ export class GlobalTable extends cdk.Construct { constructor(scope: cdk.Construct, id: string, props: GlobalTableProps) { super(scope, id); - this.construct.addWarning('The @aws-cdk/aws-dynamodb-global module has been deprecated in favor of @aws-cdk/aws-dynamodb.Table.replicationRegions'); + this.node.addWarning('The @aws-cdk/aws-dynamodb-global module has been deprecated in favor of @aws-cdk/aws-dynamodb.Table.replicationRegions'); this._regionalTables = []; diff --git a/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts b/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts index 077fdd73276b6..e68f9230b69cd 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts +++ b/packages/@aws-cdk/aws-dynamodb-global/test/test.dynamodb.global.ts @@ -24,9 +24,9 @@ export = { 'global dynamo'(test: Test) { const stack = new Stack(); new GlobalTable(stack, CONSTRUCT_NAME, STACK_PROPS); - const topStack = stack.construct.findChild(CONSTRUCT_NAME) as Stack; + const topStack = stack.node.findChild(CONSTRUCT_NAME) as Stack; for ( const reg of STACK_PROPS.regions ) { - const tableStack = topStack.construct.findChild(CONSTRUCT_NAME + '-' + reg) as Stack; + const tableStack = topStack.node.findChild(CONSTRUCT_NAME + '-' + reg) as Stack; expect(tableStack).to(haveResource('AWS::DynamoDB::Table', { 'KeySchema': [ { @@ -46,7 +46,7 @@ export = { 'TableName': 'GlobalTable', })); } - const customResourceStack = stack.construct.findChild(CONSTRUCT_NAME + '-CustomResource') as Stack; + const customResourceStack = stack.node.findChild(CONSTRUCT_NAME + '-CustomResource') as Stack; expect(customResourceStack).to(haveResource('AWS::Lambda::Function', { Description: 'Lambda to make DynamoDB a global table', Handler: 'index.handler', diff --git a/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts b/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts index 357306ee82ef0..dbfd8761aff05 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/replica-provider.ts @@ -11,7 +11,7 @@ export class ReplicaProvider extends NestedStack { public static getOrCreate(scope: Construct) { const stack = Stack.of(scope); const uid = '@aws-cdk/aws-dynamodb.ReplicaProvider'; - return stack.construct.tryFindChild(uid) as ReplicaProvider || new ReplicaProvider(stack, uid); + return stack.node.tryFindChild(uid) as ReplicaProvider || new ReplicaProvider(stack, uid); } /** diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index 66aecf2e402c7..2cb849d669f72 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -527,7 +527,7 @@ abstract class TableBase extends Resource implements ITable { */ public grantStream(grantee: iam.IGrantable, ...actions: string[]): iam.Grant { if (!this.tableStreamArn) { - throw new Error(`DynamoDB Streams must be enabled on the table ${this.construct.path}`); + throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`); } return iam.Grant.addToPrincipal({ @@ -558,7 +558,7 @@ abstract class TableBase extends Resource implements ITable { */ public grantTableListStreams(grantee: iam.IGrantable): iam.Grant { if (!this.tableStreamArn) { - throw new Error(`DynamoDB Streams must be enabled on the table ${this.construct.path}`); + throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`); } return iam.Grant.addToPrincipal({ @@ -729,7 +729,7 @@ abstract class TableBase extends Resource implements ITable { } if (opts.streamActions) { if (!this.tableStreamArn) { - throw new Error(`DynamoDB Streams must be enabled on the table ${this.construct.path}`); + throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`); } const resources = [ this.tableStreamArn]; const ret = iam.Grant.addToPrincipal({ @@ -920,7 +920,7 @@ export class Table extends TableBase { }); this.tableName = this.getResourceNameAttribute(this.table.ref); - if (props.tableName) { this.construct.addMetadata('aws:cdk:hasPhysicalName', this.tableName); } + if (props.tableName) { this.node.addMetadata('aws:cdk:hasPhysicalName', this.tableName); } this.tableStreamArn = streamSpecification ? this.table.attrStreamArn : undefined; @@ -1267,7 +1267,7 @@ export class Table extends TableBase { Region: region, }, }); - currentRegion.construct.addDependency( + currentRegion.node.addDependency( onEventHandlerPolicy.policy, isCompleteHandlerPolicy.policy, ); @@ -1279,7 +1279,7 @@ export class Table extends TableBase { const createReplica = new CfnCondition(this, `StackRegionNotEquals${region}`, { expression: Fn.conditionNot(Fn.conditionEquals(region, Aws.REGION)), }); - const cfnCustomResource = currentRegion.construct.defaultChild as CfnCustomResource; + const cfnCustomResource = currentRegion.node.defaultChild as CfnCustomResource; cfnCustomResource.cfnOptions.condition = createReplica; } @@ -1295,7 +1295,7 @@ export class Table extends TableBase { // have multiple table updates at the same time. The `isCompleteHandler` // of the provider waits until the replica is in an ACTIVE state. if (previousRegion) { - currentRegion.construct.addDependency(previousRegion); + currentRegion.node.addDependency(previousRegion); } previousRegion = currentRegion; } @@ -1349,7 +1349,7 @@ export class Table extends TableBase { switch (encryptionType) { case TableEncryption.CUSTOMER_MANAGED: const encryptionKey = props.encryptionKey ?? new kms.Key(this, 'Key', { - description: `Customer-managed key auto-created for encrypting DynamoDB table at ${this.construct.path}`, + description: `Customer-managed key auto-created for encrypting DynamoDB table at ${this.node.path}`, enableKeyRotation: true, }); @@ -1454,7 +1454,7 @@ class SourceTableAttachedPolicy extends Construct implements iam.IGrantable { public readonly policy: iam.IPolicy; public constructor(sourceTable: Table, role: iam.IRole) { - super(sourceTable, `SourceTableAttachedPolicy-${role.construct.uniqueId}`); + super(sourceTable, `SourceTableAttachedPolicy-${role.node.uniqueId}`); const policy = new iam.Policy(this, 'Resource', { roles: [role] }); this.policy = policy; diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 379613c699b92..754a30150ace5 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -324,7 +324,7 @@ test('when specifying every property', () => { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY, }); - table.construct.applyAspect(new Tag('Environment', 'Production')); + table.node.applyAspect(new Tag('Environment', 'Production')); expect(stack).toHaveResource('AWS::DynamoDB::Table', { @@ -357,7 +357,7 @@ test('when specifying sse with customer managed CMK', () => { encryption: TableEncryption.CUSTOMER_MANAGED, partitionKey: TABLE_PARTITION_KEY, }); - table.construct.applyAspect(new Tag('Environment', 'Production')); + table.node.applyAspect(new Tag('Environment', 'Production')); expect(stack).toHaveResource('AWS::DynamoDB::Table', { 'SSESpecification': { @@ -383,7 +383,7 @@ test('when specifying only encryptionKey', () => { encryptionKey, partitionKey: TABLE_PARTITION_KEY, }); - table.construct.applyAspect(new Tag('Environment', 'Production')); + table.node.applyAspect(new Tag('Environment', 'Production')); expect(stack).toHaveResource('AWS::DynamoDB::Table', { 'SSESpecification': { @@ -410,7 +410,7 @@ test('when specifying sse with customer managed CMK with encryptionKey provided encryptionKey, partitionKey: TABLE_PARTITION_KEY, }); - table.construct.applyAspect(new Tag('Environment', 'Production')); + table.node.applyAspect(new Tag('Environment', 'Production')); expect(stack).toHaveResource('AWS::DynamoDB::Table', { 'SSESpecification': { diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts index 6c8d3f2899f80..3304c8defec2e 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts @@ -58,7 +58,7 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL removalPolicy: RemovalPolicy.DESTROY, }); -tableWithGlobalAndLocalSecondaryIndex.construct.applyAspect(new Tag('Environment', 'Production')); +tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ indexName: GSI_TEST_CASE_1, diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts index 6b3777f439a4d..b1f3dca8b75a3 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.sse.ts @@ -58,7 +58,7 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL removalPolicy: RemovalPolicy.DESTROY, }); -tableWithGlobalAndLocalSecondaryIndex.construct.applyAspect(new Tag('Environment', 'Production')); +tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ indexName: GSI_TEST_CASE_1, partitionKey: GSI_PARTITION_KEY, diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts index d2fe0f276d9fe..35c81b6486d3b 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts @@ -56,7 +56,7 @@ const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL removalPolicy: RemovalPolicy.DESTROY, }); -tableWithGlobalAndLocalSecondaryIndex.construct.applyAspect(new Tag('Environment', 'Production')); +tableWithGlobalAndLocalSecondaryIndex.node.applyAspect(new Tag('Environment', 'Production')); tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({ indexName: GSI_TEST_CASE_1, partitionKey: GSI_PARTITION_KEY, diff --git a/packages/@aws-cdk/aws-ec2/lib/instance.ts b/packages/@aws-cdk/aws-ec2/lib/instance.ts index 4e27914aa5ea2..79a6bb262d053 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance.ts @@ -267,7 +267,7 @@ export class Instance extends Resource implements IInstance { } this.connections = new Connections({ securityGroups: [this.securityGroup] }); this.securityGroups.push(this.securityGroup); - Tag.add(this, NAME_TAG, props.instanceName || this.construct.path); + Tag.add(this, NAME_TAG, props.instanceName || this.node.path); this.role = props.role || new iam.Role(this, 'InstanceRole', { assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'), @@ -291,13 +291,13 @@ export class Instance extends Resource implements IInstance { if (selected.length === 1) { subnet = selected[0]; } else { - this.construct.addError(`Need exactly 1 subnet to match AZ '${props.availabilityZone}', found ${selected.length}. Use a different availabilityZone.`); + this.node.addError(`Need exactly 1 subnet to match AZ '${props.availabilityZone}', found ${selected.length}. Use a different availabilityZone.`); } } else { if (subnets.length > 0) { subnet = subnets[0]; } else { - this.construct.addError(`Did not find any subnets matching '${JSON.stringify(props.vpcSubnets)}', please use a different selection.`); + this.node.addError(`Did not find any subnets matching '${JSON.stringify(props.vpcSubnets)}', please use a different selection.`); } } if (!subnet) { @@ -322,10 +322,10 @@ export class Instance extends Resource implements IInstance { blockDeviceMappings: props.blockDevices !== undefined ? synthesizeBlockDeviceMappings(this, props.blockDevices) : undefined, privateIpAddress: props.privateIpAddress, }); - this.instance.construct.addDependency(this.role); + this.instance.node.addDependency(this.role); this.osType = imageConfig.osType; - this.construct.defaultChild = this.instance; + this.node.defaultChild = this.instance; this.instanceId = this.instance.ref; this.instanceAvailabilityZone = this.instance.attrAvailabilityZone; diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index 712c7d3cb2aa3..e5dc208be10f0 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -70,7 +70,7 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { } public get uniqueId() { - return this.construct.uniqueId; + return this.node.uniqueId; } public addIngressRule(peer: IPeer, connection: Port, description?: string, remoteRule?: boolean) { @@ -81,7 +81,7 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { const [scope, id] = determineRuleScope(this, peer, connection, 'from', remoteRule); // Skip duplicates - if (scope.construct.tryFindChild(id) === undefined) { + if (scope.node.tryFindChild(id) === undefined) { new CfnSecurityGroupIngress(scope, id, { groupId: this.securityGroupId, ...peer.toIngressRuleConfig(), @@ -99,7 +99,7 @@ abstract class SecurityGroupBase extends Resource implements ISecurityGroup { const [scope, id] = determineRuleScope(this, peer, connection, 'to', remoteRule); // Skip duplicates - if (scope.construct.tryFindChild(id) === undefined) { + if (scope.node.tryFindChild(id) === undefined) { new CfnSecurityGroupEgress(scope, id, { groupId: this.securityGroupId, ...peer.toEgressRuleConfig(), @@ -363,7 +363,7 @@ export class SecurityGroup extends SecurityGroupBase { physicalName: props.securityGroupName, }); - const groupDescription = props.description || this.construct.path; + const groupDescription = props.description || this.node.path; this.allowAllOutbound = props.allowAllOutbound !== false; @@ -404,7 +404,7 @@ export class SecurityGroup extends SecurityGroupBase { // In the case of "allowAllOutbound", we don't add any more rules. There // is only one rule which allows all traffic and that subsumes any other // rule. - this.construct.addWarning('Ignoring Egress rule since \'allowAllOutbound\' is set to true; To add customize rules, set allowAllOutbound=false on the SecurityGroup'); + this.node.addWarning('Ignoring Egress rule since \'allowAllOutbound\' is set to true; To add customize rules, set allowAllOutbound=false on the SecurityGroup'); return; } else { // Otherwise, if the bogus rule exists we can now remove it because the diff --git a/packages/@aws-cdk/aws-ec2/lib/user-data.ts b/packages/@aws-cdk/aws-ec2/lib/user-data.ts index 78ee18fb7c824..617563e6cd05a 100644 --- a/packages/@aws-cdk/aws-ec2/lib/user-data.ts +++ b/packages/@aws-cdk/aws-ec2/lib/user-data.ts @@ -172,7 +172,7 @@ class LinuxUserData extends UserData { public addSignalOnExitCommand( resource: Resource ): void { const stack = Stack.of(resource); - const resourceID = stack.getLogicalId(resource.construct.defaultChild as CfnElement); + const resourceID = stack.getLogicalId(resource.node.defaultChild as CfnElement); this.addOnExitCommands(`/opt/aws/bin/cfn-signal --stack ${stack.stackName} --resource ${resourceID} --region ${stack.region} -e $exitCode || echo 'Failed to send Cloudformation Signal'`); } @@ -230,7 +230,7 @@ class WindowsUserData extends UserData { public addSignalOnExitCommand( resource: Resource ): void { const stack = Stack.of(resource); - const resourceID = stack.getLogicalId(resource.construct.defaultChild as CfnElement); + const resourceID = stack.getLogicalId(resource.node.defaultChild as CfnElement); this.addOnExitCommands(`cfn-signal --stack ${stack.stackName} --resource ${resourceID} --region ${stack.region} --success ($success.ToString().ToLower())`); } diff --git a/packages/@aws-cdk/aws-ec2/lib/util.ts b/packages/@aws-cdk/aws-ec2/lib/util.ts index 91c0cd186960d..4f5a765b96bc5 100644 --- a/packages/@aws-cdk/aws-ec2/lib/util.ts +++ b/packages/@aws-cdk/aws-ec2/lib/util.ts @@ -27,7 +27,7 @@ export function defaultSubnetName(type: SubnetType) { * All subnet names look like NAME <> "Subnet" <> INDEX */ export function subnetGroupNameFromConstructId(subnet: ISubnet) { - return subnet.construct.id.replace(/Subnet\d+$/, ''); + return subnet.node.id.replace(/Subnet\d+$/, ''); } /** diff --git a/packages/@aws-cdk/aws-ec2/lib/volume.ts b/packages/@aws-cdk/aws-ec2/lib/volume.ts index ce62244e499c3..e33c32a9d63b6 100644 --- a/packages/@aws-cdk/aws-ec2/lib/volume.ts +++ b/packages/@aws-cdk/aws-ec2/lib/volume.ts @@ -176,7 +176,7 @@ export function synthesizeBlockDeviceMappings(construct: Construct, blockDevices throw new Error('iops property is required with volumeType: EbsDeviceVolumeType.IO1'); } } else if (volumeType !== EbsDeviceVolumeType.IO1) { - construct.construct.addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + construct.node.addWarning('iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); } } @@ -556,7 +556,7 @@ abstract class VolumeBase extends Resource implements IVolume { private calculateResourceTagValue(constructs: Construct[]): string { const md5 = crypto.createHash('md5'); - constructs.forEach(construct => md5.update(construct.construct.uniqueId)); + constructs.forEach(construct => md5.update(construct.node.uniqueId)); return md5.digest('hex'); } } diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index ff53488411938..daaba4cd8a05f 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -377,7 +377,7 @@ abstract class VpcBase extends Resource implements IVpc { const routeTableIds = allRouteTableIds(flatten(vpnRoutePropagation.map(s => this.selectSubnets(s).subnets))); if (routeTableIds.length === 0) { - this.construct.addError(`enableVpnGateway: no subnets matching selection: '${JSON.stringify(vpnRoutePropagation)}'. Select other subnets to add routes to.`); + this.node.addError(`enableVpnGateway: no subnets matching selection: '${JSON.stringify(vpnRoutePropagation)}'. Select other subnets to add routes to.`); } const routePropagation = new CfnVPNGatewayRoutePropagation(this, 'RoutePropagation', { @@ -387,7 +387,7 @@ abstract class VpcBase extends Resource implements IVpc { // The AWS::EC2::VPNGatewayRoutePropagation resource cannot use the VPN gateway // until it has successfully attached to the VPC. // See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpn-gatewayrouteprop.html - routePropagation.construct.addDependency(attachment); + routePropagation.node.addDependency(attachment); } /** @@ -1176,7 +1176,7 @@ export class Vpc extends VpcBase { this.vpcDefaultSecurityGroup = this.resource.attrDefaultSecurityGroup; this.vpcIpv6CidrBlocks = this.resource.attrIpv6CidrBlocks; - this.construct.applyAspect(new Tag(NAME_TAG, this.construct.path)); + this.node.applyAspect(new Tag(NAME_TAG, this.node.path)); this.availabilityZones = stack.availabilityZones; @@ -1363,8 +1363,8 @@ export class Vpc extends VpcBase { // These values will be used to recover the config upon provider import const includeResourceTypes = [CfnSubnet.CFN_RESOURCE_TYPE_NAME]; - subnet.construct.applyAspect(new Tag(SUBNETNAME_TAG, subnetConfig.name, {includeResourceTypes})); - subnet.construct.applyAspect(new Tag(SUBNETTYPE_TAG, subnetTypeTagValue(subnetConfig.subnetType), {includeResourceTypes})); + subnet.node.applyAspect(new Tag(SUBNETNAME_TAG, subnetConfig.name, {includeResourceTypes})); + subnet.node.applyAspect(new Tag(SUBNETTYPE_TAG, subnetTypeTagValue(subnetConfig.subnetType), {includeResourceTypes})); }); } } @@ -1482,7 +1482,7 @@ export class Subnet extends Resource implements ISubnet { Object.defineProperty(this, VPC_SUBNET_SYMBOL, { value: true }); - this.construct.applyAspect(new Tag(NAME_TAG, this.construct.path)); + this.node.applyAspect(new Tag(NAME_TAG, this.node.path)); this.availabilityZone = props.availabilityZone; const subnet = new CfnSubnet(this, 'Subnet', { @@ -1500,7 +1500,7 @@ export class Subnet extends Resource implements ISubnet { // was just created. However, the ACL can be replaced at a later time. this._networkAcl = NetworkAcl.fromNetworkAclId(this, 'Acl', subnet.attrNetworkAclAssociationId); this.subnetNetworkAclAssociationId = Lazy.stringValue({ produce: () => this._networkAcl.networkAclId }); - this.construct.defaultChild = subnet; + this.node.defaultChild = subnet; const table = new CfnRouteTable(this, 'RouteTable', { vpcId: props.vpcId, @@ -1529,7 +1529,7 @@ export class Subnet extends Resource implements ISubnet { destinationCidrBlock: '0.0.0.0/0', gatewayId, }); - route.construct.addDependency(gatewayAttachment); + route.node.addDependency(gatewayAttachment); // Since the 'route' depends on the gateway attachment, just // depending on the route is enough. @@ -1587,7 +1587,7 @@ export class Subnet extends Resource implements ISubnet { const scope = Construct.isConstruct(networkAcl) ? networkAcl : this; const other = Construct.isConstruct(networkAcl) ? this : networkAcl; - new SubnetNetworkAclAssociation(scope, id + other.construct.uniqueId, { + new SubnetNetworkAclAssociation(scope, id + other.node.uniqueId, { networkAcl, subnet: this, }); @@ -1891,10 +1891,10 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat if (!attrs.routeTableId) { const ref = Token.isUnresolved(attrs.subnetId) - ? `at '${scope.construct.path}/${id}'` + ? `at '${scope.node.path}/${id}'` : `'${attrs.subnetId}'`; // eslint-disable-next-line max-len - scope.construct.addWarning(`No routeTableId was provided to the subnet ${ref}. Attempting to read its .routeTable.routeTableId will return null/undefined. (More info: https://github.com/aws/aws-cdk/pull/3171)`); + scope.node.addWarning(`No routeTableId was provided to the subnet ${ref}. Attempting to read its .routeTable.routeTableId will return null/undefined. (More info: https://github.com/aws/aws-cdk/pull/3171)`); } this._availabilityZone = attrs.availabilityZone; @@ -1916,7 +1916,7 @@ class ImportedSubnet extends Resource implements ISubnet, IPublicSubnet, IPrivat public associateNetworkAcl(id: string, networkAcl: INetworkAcl): void { const scope = Construct.isConstruct(networkAcl) ? networkAcl : this; const other = Construct.isConstruct(networkAcl) ? this : networkAcl; - new SubnetNetworkAclAssociation(scope, id + other.construct.uniqueId, { + new SubnetNetworkAclAssociation(scope, id + other.node.uniqueId, { networkAcl, subnet: this, }); diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index ed451b1a774e7..2a78f3cdf516e 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -237,8 +237,8 @@ nodeunitShim({ }); // THEN - test.deepEqual(instance.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(instance.construct.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + test.deepEqual(instance.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(instance.node.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); test.done(); }, @@ -264,8 +264,8 @@ nodeunitShim({ }); // THEN - test.deepEqual(instance.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(instance.construct.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); + test.deepEqual(instance.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(instance.node.metadata[0].data, 'iops will be ignored without volumeType: EbsDeviceVolumeType.IO1'); test.done(); }, diff --git a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts index 5f2baf4eec680..a1c8e39c28141 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc-endpoint.test.ts @@ -393,13 +393,13 @@ nodeunitShim({ const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } }); // Setup context for stack AZs - stack.construct.setContext( + stack.node.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER, }).key, ['us-east-1a', 'us-east-1b', 'us-east-1c']); // Setup context for endpoint service AZs - stack.construct.setContext( + stack.node.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER, props: { @@ -438,7 +438,7 @@ nodeunitShim({ const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } }); // Setup context for stack AZs - stack.construct.setContext( + stack.node.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER, }).key, @@ -477,13 +477,13 @@ nodeunitShim({ const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-east-1' } }); // Setup context for stack AZs - stack.construct.setContext( + stack.node.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER, }).key, ['us-east-1a', 'us-east-1b', 'us-east-1c']); // Setup context for endpoint service AZs - stack.construct.setContext( + stack.node.setContext( ContextProvider.getKey(stack, { provider: cxschema.ContextProvider.ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER, props: { diff --git a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts index d2156a067e899..113a8eb7edd56 100644 --- a/packages/@aws-cdk/aws-ec2/test/vpc.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/vpc.test.ts @@ -807,7 +807,7 @@ nodeunitShim({ const vpc = new Vpc(stack, 'VpcNetwork'); - test.ok(vpc.publicSubnets[0].construct.defaultChild instanceof CfnSubnet); + test.ok(vpc.publicSubnets[0].node.defaultChild instanceof CfnSubnet); test.done(); }, @@ -1033,8 +1033,8 @@ nodeunitShim({ const vpc = new Vpc(stack, 'TheVPC'); // overwrite to set propagate - vpc.construct.applyAspect(new Tag('BusinessUnit', 'Marketing', {includeResourceTypes: [CfnVPC.CFN_RESOURCE_TYPE_NAME]})); - vpc.construct.applyAspect(new Tag('VpcType', 'Good')); + vpc.node.applyAspect(new Tag('BusinessUnit', 'Marketing', {includeResourceTypes: [CfnVPC.CFN_RESOURCE_TYPE_NAME]})); + vpc.node.applyAspect(new Tag('VpcType', 'Good')); expect(stack).to(haveResource('AWS::EC2::VPC', hasTags(toCfnTags(allTags)))); const taggables = ['Subnet', 'InternetGateway', 'NatGateway', 'RouteTable']; const propTags = toCfnTags(tags); @@ -1049,12 +1049,12 @@ nodeunitShim({ const stack = getTestStack(); const vpc = new Vpc(stack, 'TheVPC'); for (const subnet of vpc.publicSubnets) { - const tag = {Key: 'Name', Value: subnet.construct.path}; + const tag = {Key: 'Name', Value: subnet.node.path}; expect(stack).to(haveResource('AWS::EC2::NatGateway', hasTags([tag]))); expect(stack).to(haveResource('AWS::EC2::RouteTable', hasTags([tag]))); } for (const subnet of vpc.privateSubnets) { - const tag = {Key: 'Name', Value: subnet.construct.path}; + const tag = {Key: 'Name', Value: subnet.node.path}; expect(stack).to(haveResource('AWS::EC2::RouteTable', hasTags([tag]))); } test.done(); @@ -1065,7 +1065,7 @@ nodeunitShim({ const vpc = new Vpc(stack, 'TheVPC'); const tag = {Key: 'Late', Value: 'Adder'}; expect(stack).notTo(haveResource('AWS::EC2::VPC', hasTags([tag]))); - vpc.construct.applyAspect(new Tag(tag.Key, tag.Value)); + vpc.node.applyAspect(new Tag(tag.Key, tag.Value)); expect(stack).to(haveResource('AWS::EC2::VPC', hasTags([tag]))); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts index 07a297e9642b6..09c4a033a8476 100644 --- a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts +++ b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts @@ -112,7 +112,7 @@ export class DockerImageAsset extends Construct implements assets.IAsset { }); if (props.repositoryName) { - this.construct.addWarning('DockerImageAsset.repositoryName is deprecated. Override "core.Stack.addDockerImageAsset" to control asset locations'); + this.node.addWarning('DockerImageAsset.repositoryName is deprecated. Override "core.Stack.addDockerImageAsset" to control asset locations'); } // include build context in "extra" so it will impact the hash diff --git a/packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts b/packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts index d3affe4b26799..54930ec176e14 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/test.image-asset.ts @@ -50,7 +50,7 @@ export = { }); // THEN - const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).buildArgs, { a: 'b' }); test.done(); }, @@ -69,7 +69,7 @@ export = { }); // THEN - const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).target, 'a-target'); test.done(); }, @@ -86,7 +86,7 @@ export = { }); // THEN - const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.deepEqual(assetMetadata && (assetMetadata.data as cxschema.ContainerImageAssetMetadataEntry).file, 'Dockerfile.Custom'); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts index 341307af9b88f..3869d38d8826a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts @@ -380,9 +380,9 @@ export abstract class ApplicationLoadBalancedServiceBase extends cdk.Construct { */ protected getDefaultCluster(scope: cdk.Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; const stack = cdk.Stack.of(scope); - return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-multiple-target-groups-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-multiple-target-groups-service-base.ts index f813f1431a966..5764b3fcdaeb5 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-multiple-target-groups-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-multiple-target-groups-service-base.ts @@ -385,9 +385,9 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru this.listeners.push(listener); } const domainName = this.createDomainName(lb, lbProps.domainName, lbProps.domainZone); - new CfnOutput(this, `LoadBalancerDNS${lb.construct.id}`, { value: lb.loadBalancerDnsName }); + new CfnOutput(this, `LoadBalancerDNS${lb.node.id}`, { value: lb.loadBalancerDnsName }); for (const protocol of protocolType) { - new CfnOutput(this, `ServiceURL${lb.construct.id}${protocol.toLowerCase()}`, { value: protocol.toLowerCase() + '://' + domainName }); + new CfnOutput(this, `ServiceURL${lb.node.id}${protocol.toLowerCase()}`, { value: protocol.toLowerCase() + '://' + domainName }); } } // set up default load balancer and listener. @@ -412,9 +412,9 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru */ protected getDefaultCluster(scope: Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs. - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; const stack = Stack.of(scope); - return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } protected createAWSLogDriver(prefix: string): AwsLogDriver { @@ -426,7 +426,7 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru return this.listener; } for (const listener of this.listeners) { - if (listener.construct.id === name) { + if (listener.node.id === name) { return listener; } } @@ -474,7 +474,7 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru const enableLogging = enableLoggingProp !== undefined ? enableLoggingProp : true; const logDriver = logDriverProp !== undefined ? logDriverProp : enableLogging - ? this.createAWSLogDriver(this.construct.id) : undefined; + ? this.createAWSLogDriver(this.node.id) : undefined; return logDriver; } @@ -558,7 +558,7 @@ export abstract class ApplicationMultipleTargetGroupsServiceBase extends Constru throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name'); } - const record = new ARecord(this, `DNS${loadBalancer.construct.id}`, { + const record = new ARecord(this, `DNS${loadBalancer.node.id}`, { zone, recordName: name, target: RecordTarget.fromAlias(new LoadBalancerTarget(loadBalancer)), diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts index 070fb96a4f868..567e952140b5b 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts @@ -314,9 +314,9 @@ export abstract class NetworkLoadBalancedServiceBase extends cdk.Construct { */ protected getDefaultCluster(scope: cdk.Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; const stack = cdk.Stack.of(scope); - return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts index 559451645a688..54ec00ef64b1a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-multiple-target-groups-service-base.ts @@ -304,7 +304,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { this.listeners.push(listener); } this.createDomainName(lb, lbProps.domainName, lbProps.domainZone); - new CfnOutput(this, `LoadBalancerDNS${lb.construct.id}`, { value: lb.loadBalancerDnsName }); + new CfnOutput(this, `LoadBalancerDNS${lb.node.id}`, { value: lb.loadBalancerDnsName }); } // set up default load balancer and listener. this.loadBalancer = this.loadBalancers[0]; @@ -323,9 +323,9 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { */ protected getDefaultCluster(scope: Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs. - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; const stack = Stack.of(scope); - return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } protected createAWSLogDriver(prefix: string): AwsLogDriver { @@ -337,7 +337,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { return this.listener; } for (const listener of this.listeners) { - if (listener.construct.id === name) { + if (listener.node.id === name) { return listener; } } @@ -380,7 +380,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { const enableLogging = enableLoggingProp !== undefined ? enableLoggingProp : true; const logDriver = logDriverProp !== undefined ? logDriverProp : enableLogging - ? this.createAWSLogDriver(this.construct.id) : undefined; + ? this.createAWSLogDriver(this.node.id) : undefined; return logDriver; } @@ -427,7 +427,7 @@ export abstract class NetworkMultipleTargetGroupsServiceBase extends Construct { throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name'); } - new ARecord(this, `DNS${loadBalancer.construct.id}`, { + new ARecord(this, `DNS${loadBalancer.node.id}`, { zone, recordName: name, target: RecordTarget.fromAlias(new LoadBalancerTarget(loadBalancer)), diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts index f5a3f4c2b0e64..cd9e2f85f4633 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts @@ -256,7 +256,7 @@ export abstract class QueueProcessingServiceBase extends Construct { this.logDriver = props.logDriver !== undefined ? props.logDriver : enableLogging - ? this.createAWSLogDriver(this.construct.id) + ? this.createAWSLogDriver(this.node.id) : undefined; // Add the queue name to environment variables @@ -304,9 +304,9 @@ export abstract class QueueProcessingServiceBase extends Construct { */ protected getDefaultCluster(scope: Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; const stack = Stack.of(scope); - return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts index 5d972bfad47e6..47f14de90e59a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/scheduled-task-base.ts @@ -161,9 +161,9 @@ export abstract class ScheduledTaskBase extends Construct { */ protected getDefaultCluster(scope: Construct, vpc?: IVpc): Cluster { // magic string to avoid collision with user-defined constructs - const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.construct.id : ''}`; + const DEFAULT_CLUSTER_ID = `EcsDefaultClusterMnL3mNNYN${vpc ? vpc.node.id : ''}`; const stack = Stack.of(scope); - return stack.construct.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); + return stack.node.tryFindChild(DEFAULT_CLUSTER_ID) as Cluster || new Cluster(stack, DEFAULT_CLUSTER_ID, { vpc }); } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts index 46e37fd4fdd09..f38cdbba5e3ca 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts @@ -100,7 +100,7 @@ export class ApplicationLoadBalancedEc2Service extends ApplicationLoadBalancedSe const enableLogging = taskImageOptions.enableLogging !== undefined ? taskImageOptions.enableLogging : true; const logDriver = taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : enableLogging - ? this.createAWSLogDriver(this.construct.id) : undefined; + ? this.createAWSLogDriver(this.node.id) : undefined; const containerName = taskImageOptions.containerName !== undefined ? taskImageOptions.containerName : 'web'; const container = this.taskDefinition.addContainer(containerName, { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts index 8a1fb21af8995..f6738f52ac687 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts @@ -98,7 +98,7 @@ export class NetworkLoadBalancedEc2Service extends NetworkLoadBalancedServiceBas const enableLogging = taskImageOptions.enableLogging !== undefined ? taskImageOptions.enableLogging : true; const logDriver = taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : enableLogging - ? this.createAWSLogDriver(this.construct.id) : undefined; + ? this.createAWSLogDriver(this.node.id) : undefined; const containerName = taskImageOptions.containerName !== undefined ? taskImageOptions.containerName : 'web'; const container = this.taskDefinition.addContainer(containerName, { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/scheduled-ecs-task.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/scheduled-ecs-task.ts index ab4f89b5f851f..7f0776dc812d4 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/scheduled-ecs-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/scheduled-ecs-task.ts @@ -107,7 +107,7 @@ export class ScheduledEc2Task extends ScheduledTaskBase { command: taskImageOptions.command, environment: taskImageOptions.environment, secrets: taskImageOptions.secrets, - logging: taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : this.createAWSLogDriver(this.construct.id), + logging: taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : this.createAWSLogDriver(this.node.id), }); } else { throw new Error('You must specify a taskDefinition or image'); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts index b148eebbcd78f..baa8a191410dc 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts @@ -122,7 +122,7 @@ export class ApplicationLoadBalancedFargateService extends ApplicationLoadBalanc const enableLogging = taskImageOptions.enableLogging !== undefined ? taskImageOptions.enableLogging : true; const logDriver = taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : enableLogging - ? this.createAWSLogDriver(this.construct.id) : undefined; + ? this.createAWSLogDriver(this.node.id) : undefined; const containerName = taskImageOptions.containerName !== undefined ? taskImageOptions.containerName : 'web'; const container = this.taskDefinition.addContainer(containerName, { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts index 91fe54ce83734..c86e279ab2ea1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts @@ -118,7 +118,7 @@ export class NetworkLoadBalancedFargateService extends NetworkLoadBalancedServic const enableLogging = taskImageOptions.enableLogging !== undefined ? taskImageOptions.enableLogging : true; const logDriver = taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : enableLogging - ? this.createAWSLogDriver(this.construct.id) : undefined; + ? this.createAWSLogDriver(this.node.id) : undefined; const containerName = taskImageOptions.containerName !== undefined ? taskImageOptions.containerName : 'web'; const container = this.taskDefinition.addContainer(containerName, { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/scheduled-fargate-task.ts index d4a79b3315bf8..e2c3dec274de8 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/scheduled-fargate-task.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/scheduled-fargate-task.ts @@ -103,7 +103,7 @@ export class ScheduledFargateTask extends ScheduledTaskBase { command: taskImageOptions.command, environment: taskImageOptions.environment, secrets: taskImageOptions.secrets, - logging: taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : this.createAWSLogDriver(this.construct.id), + logging: taskImageOptions.logDriver !== undefined ? taskImageOptions.logDriver : this.createAWSLogDriver(this.node.id), }); } else { throw new Error('You must specify one of: taskDefinition or image'); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts index 152f41ff1e92f..745bad2c660fc 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts @@ -502,9 +502,9 @@ export = { }); // THEN - test.equal(ecsService.loadBalancer.construct.id, 'lb1'); - test.equal(ecsService.listener.construct.id, 'listener1'); - test.equal(ecsService.targetGroup.construct.id, 'ECSTargetGroupweb80Group'); + test.equal(ecsService.loadBalancer.node.id, 'lb1'); + test.equal(ecsService.listener.node.id, 'listener1'); + test.equal(ecsService.targetGroup.node.id, 'ECSTargetGroupweb80Group'); test.done(); }, @@ -1241,9 +1241,9 @@ export = { }); // THEN - test.equal(ecsService.loadBalancer.construct.id, 'lb1'); - test.equal(ecsService.listener.construct.id, 'listener1'); - test.equal(ecsService.targetGroup.construct.id, 'ECSTargetGroupweb80Group'); + test.equal(ecsService.loadBalancer.node.id, 'lb1'); + test.equal(ecsService.listener.node.id, 'listener1'); + test.equal(ecsService.targetGroup.node.id, 'ECSTargetGroupweb80Group'); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.ts index 9e0ac7a1e2403..f4ecc0f0a5616 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.ts @@ -1,7 +1,6 @@ import { Vpc } from '@aws-cdk/aws-ec2'; import { Cluster, ContainerImage } from '@aws-cdk/aws-ecs'; import { ApplicationProtocol } from '@aws-cdk/aws-elasticloadbalancingv2'; -import { HostedZone } from '@aws-cdk/aws-route53'; import { App, Stack } from '@aws-cdk/core'; import { ApplicationLoadBalancedFargateService } from '../../lib'; @@ -21,10 +20,13 @@ new ApplicationLoadBalancedFargateService(stack, 'myService', { protocol: ApplicationProtocol.HTTPS, enableECSManagedTags: true, domainName: 'test.example.com', - domainZone: HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + domainZone: { hostedZoneId: 'fakeId', - zoneName: 'example.com', - }), + zoneName: 'example.com.', + hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', + stack, + node: stack.node, + }, }); app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts index aed0414695b64..4b30dfa721480 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts @@ -3,7 +3,6 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecs from '@aws-cdk/aws-ecs'; import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; import * as iam from '@aws-cdk/aws-iam'; -import * as route53 from '@aws-cdk/aws-route53'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as ecsPatterns from '../../lib'; @@ -371,10 +370,13 @@ export = { cluster, protocol: ApplicationProtocol.HTTPS, domainName: 'domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'MyHostedZone', { + domainZone: { hostedZoneId: 'fakeId', zoneName: 'domain.com', - }), + hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', + stack, + node: stack.node, + }, taskImageOptions: { containerPort: 2015, image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), @@ -406,10 +408,13 @@ export = { cluster, protocol: ApplicationProtocol.HTTPS, domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'MyHostedZone', { + domainZone: { hostedZoneId: 'fakeId', zoneName: 'domain.com.', - }), + hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', + stack, + node: stack.node, + }, taskImageOptions: { containerPort: 2015, image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index eadff8f528b8a..3f00c03bc70af 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -356,7 +356,7 @@ export abstract class BaseService extends Resource }); if (props.deploymentController?.type === DeploymentControllerType.EXTERNAL) { - this.construct.addWarning('taskDefinition and launchType are blanked out when using external deployment controller.'); + this.node.addWarning('taskDefinition and launchType are blanked out when using external deployment controller.'); } this.serviceArn = this.getResourceArnAttribute(this.resource.ref, { @@ -675,7 +675,7 @@ export abstract class BaseService extends Resource // Service creation can only happen after the load balancer has // been associated with our target group(s), so add ordering dependency. - this.resource.construct.addDependency(targetGroup.loadBalancerAttached); + this.resource.node.addDependency(targetGroup.loadBalancerAttached); const targetType = this.taskDefinition.networkMode === NetworkMode.AWS_VPC ? elbv2.TargetType.IP : elbv2.TargetType.INSTANCE; return { targetType }; diff --git a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts index 8be911a2a0cfd..94bc5bbef39b4 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts @@ -266,7 +266,7 @@ export class TaskDefinition extends TaskDefinitionBase { constructor(scope: Construct, id: string, props: TaskDefinitionProps) { super(scope, id); - this.family = props.family || this.construct.uniqueId; + this.family = props.family || this.node.uniqueId; this.compatibility = props.compatibility; if (props.volumes) { diff --git a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts index cdcf56e8a494c..26da3b453bf46 100644 --- a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts @@ -377,7 +377,7 @@ export class ContainerDefinition extends cdk.Construct { this.taskDefinition = props.taskDefinition; this.memoryLimitSpecified = props.memoryLimitMiB !== undefined || props.memoryReservationMiB !== undefined; this.linuxParameters = props.linuxParameters; - this.containerName = this.construct.id; + this.containerName = this.node.id; this.imageConfig = props.image.bind(this, this); if (props.logging) { @@ -389,7 +389,7 @@ export class ContainerDefinition extends cdk.Construct { this.secrets = []; for (const [name, secret] of Object.entries(props.secrets)) { if (this.taskDefinition.isFargateCompatible && secret.hasField) { - throw new Error(`Cannot specify secret JSON field for a task using the FARGATE launch type: '${name}' in container '${this.construct.id}'`); + throw new Error(`Cannot specify secret JSON field for a task using the FARGATE launch type: '${name}' in container '${this.node.id}'`); } secret.grantRead(this.taskDefinition.obtainExecutionRole()); this.secrets.push({ diff --git a/packages/@aws-cdk/aws-ecs/lib/images/repository.ts b/packages/@aws-cdk/aws-ecs/lib/images/repository.ts index b9419720d409c..95d3675d63e11 100644 --- a/packages/@aws-cdk/aws-ecs/lib/images/repository.ts +++ b/packages/@aws-cdk/aws-ecs/lib/images/repository.ts @@ -37,7 +37,7 @@ export class RepositoryImage extends ContainerImage { public bind(scope: Construct, containerDefinition: ContainerDefinition): ContainerImageConfig { // name could be a Token - in that case, skip validation altogether if (!Token.isUnresolved(this.imageName) && ECR_IMAGE_REGEX.test(this.imageName)) { - scope.construct.addWarning("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + scope.node.addWarning("Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); } if (this.props.credentials) { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts index fb2a10c6823ec..6b74bcf656e9a 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts @@ -443,7 +443,7 @@ export = { }); // THEN - test.deepEqual(service.construct.metadata[0].data, 'taskDefinition and launchType are blanked out when using external deployment controller.'); + test.deepEqual(service.node.metadata[0].data, 'taskDefinition and launchType are blanked out when using external deployment controller.'); expect(stack).to(haveResource('AWS::ECS::Service', { Cluster: { Ref: 'EcsCluster97242B84', diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts index 0559394e98e1a..a22c4801fcebb 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts @@ -519,7 +519,7 @@ export = { }); // THEN - test.deepEqual(container.construct.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + test.deepEqual(container.node.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); test.done(); }, @@ -538,7 +538,7 @@ export = { }); // THEN - test.deepEqual(container.construct.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); + test.deepEqual(container.node.metadata[0].data, "Proper policies need to be attached before pulling from ECR repository, or use 'fromEcrRepository'."); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts b/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts index 1ad1150804c67..991901512a6d2 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/fargate/test.fargate-service.ts @@ -321,7 +321,7 @@ export = { }); // THEN - test.deepEqual(service.construct.metadata[0].data, 'taskDefinition and launchType are blanked out when using external deployment controller.'); + test.deepEqual(service.node.metadata[0].data, 'taskDefinition and launchType are blanked out when using external deployment controller.'); expect(stack).to(haveResource('AWS::ECS::Service', { Cluster: { Ref: 'EcsCluster97242B84', diff --git a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts index bf8b1aaff76e5..854503f388f7d 100644 --- a/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts +++ b/packages/@aws-cdk/aws-efs/lib/efs-file-system.ts @@ -255,7 +255,7 @@ export class FileSystem extends Resource implements IFileSystem { filesystem.applyRemovalPolicy(props.removalPolicy); this.fileSystemId = filesystem.ref; - Tag.add(this, 'Name', props.fileSystemName || this.construct.path); + Tag.add(this, 'Name', props.fileSystemName || this.node.path); const securityGroup = (props.securityGroup || new ec2.SecurityGroup(this, 'EfsSecurityGroup', { vpc: props.vpc, diff --git a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts index 370c6bdff566e..5104c069ec061 100644 --- a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts +++ b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts @@ -210,7 +210,7 @@ test('auto-named if none provided', () => { // THEN expectCDK(stack).to(haveResource('AWS::EFS::FileSystem', { FileSystemTags: [ - {Key: 'Name', Value: fileSystem.construct.path}, + {Key: 'Name', Value: fileSystem.node.path}, ], })); }); diff --git a/packages/@aws-cdk/aws-eks-legacy/lib/cluster.ts b/packages/@aws-cdk/aws-eks-legacy/lib/cluster.ts index 19fa809081a66..0c5fcc2fb2e92 100644 --- a/packages/@aws-cdk/aws-eks-legacy/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks-legacy/lib/cluster.ts @@ -336,7 +336,7 @@ export class Cluster extends Resource implements ICluster { physicalName: props.clusterName, }); - this.construct.addWarning('The @aws-cdk/aws-eks-legacy module will no longer be released as part of the AWS CDK starting March 1st, 2020. Please refer to https://github.com/aws/aws-cdk/issues/5544 for upgrade instructions'); + this.node.addWarning('The @aws-cdk/aws-eks-legacy module will no longer be released as part of the AWS CDK starting March 1st, 2020. Please refer to https://github.com/aws/aws-cdk/issues/5544 for upgrade instructions'); const stack = Stack.of(this); @@ -636,11 +636,11 @@ export class Cluster extends Resource implements ICluster { // message (if token): "could not auto-tag public/private subnet with tag..." // message (if not token): "count not auto-tag public/private subnet xxxxx with tag..." const subnetID = Token.isUnresolved(subnet.subnetId) ? '' : ` ${subnet.subnetId}`; - this.construct.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); + this.node.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); continue; } - subnet.construct.applyAspect(new Tag(tag, '1')); + subnet.node.applyAspect(new Tag(tag, '1')); } }; diff --git a/packages/@aws-cdk/aws-eks-legacy/lib/helm-chart.ts b/packages/@aws-cdk/aws-eks-legacy/lib/helm-chart.ts index 03170db25fbca..714fc97e4da0d 100644 --- a/packages/@aws-cdk/aws-eks-legacy/lib/helm-chart.ts +++ b/packages/@aws-cdk/aws-eks-legacy/lib/helm-chart.ts @@ -84,7 +84,7 @@ export class HelmChart extends Construct { provider: CustomResourceProvider.lambda(handler), resourceType: HelmChart.RESOURCE_TYPE, properties: { - Release: props.release || this.construct.uniqueId.slice(-63).toLowerCase(), // Helm has a 63 character limit for the name + Release: props.release || this.node.uniqueId.slice(-63).toLowerCase(), // Helm has a 63 character limit for the name Chart: props.chart, Version: props.version, Values: (props.values ? stack.toJsonString(props.values) : undefined), @@ -99,7 +99,7 @@ export class HelmChart extends Construct { return undefined; } - let handler = cluster.construct.tryFindChild('HelmChartHandler') as lambda.IFunction; + let handler = cluster.node.tryFindChild('HelmChartHandler') as lambda.IFunction; if (!handler) { handler = new lambda.Function(cluster, 'HelmChartHandler', { code: lambda.Code.fromAsset(path.join(__dirname, 'helm-chart')), diff --git a/packages/@aws-cdk/aws-eks-legacy/lib/kubectl-layer.ts b/packages/@aws-cdk/aws-eks-legacy/lib/kubectl-layer.ts index 79491964f295e..73168622e4ff4 100644 --- a/packages/@aws-cdk/aws-eks-legacy/lib/kubectl-layer.ts +++ b/packages/@aws-cdk/aws-eks-legacy/lib/kubectl-layer.ts @@ -27,7 +27,7 @@ export class KubectlLayer extends Construct implements lambda.ILayerVersion { public static getOrCreate(scope: Construct, props: KubectlLayerProps = {}): KubectlLayer { const stack = Stack.of(scope); const id = 'kubectl-layer-' + (props.version ? props.version : '8C2542BC-BF2B-4DFE-B765-E181FD30A9A0'); - const exists = stack.construct.tryFindChild(id) as KubectlLayer; + const exists = stack.node.tryFindChild(id) as KubectlLayer; if (exists) { return exists; } @@ -48,7 +48,7 @@ export class KubectlLayer extends Construct implements lambda.ILayerVersion { constructor(scope: Construct, id: string, props: KubectlLayerProps = {}) { super(scope, id); - const uniqueId = crypto.createHash('md5').update(this.construct.path).digest('hex'); + const uniqueId = crypto.createHash('md5').update(this.node.path).digest('hex'); const version = props.version || KUBECTL_APP_VERSION; this.stack.templateOptions.transforms = [ 'AWS::Serverless-2016-10-31' ]; // required for AWS::Serverless diff --git a/packages/@aws-cdk/aws-eks-legacy/lib/user-data.ts b/packages/@aws-cdk/aws-eks-legacy/lib/user-data.ts index 89206b26a928d..e889663520f32 100644 --- a/packages/@aws-cdk/aws-eks-legacy/lib/user-data.ts +++ b/packages/@aws-cdk/aws-eks-legacy/lib/user-data.ts @@ -7,7 +7,7 @@ export function renderUserData(clusterName: string, autoScalingGroup: autoscalin const stack = Stack.of(autoScalingGroup); // determine logical id of ASG so we can signal cloudformation - const cfn = autoScalingGroup.construct.defaultChild as autoscaling.CfnAutoScalingGroup; + const cfn = autoScalingGroup.node.defaultChild as autoscaling.CfnAutoScalingGroup; const asgLogicalId = cfn.logicalId; const extraArgs = new Array(); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts index 3df44f8147841..f9c1a592586ca 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts @@ -19,7 +19,7 @@ export class ClusterResourceProvider extends NestedStack { public static getOrCreate(scope: Construct) { const stack = Stack.of(scope); const uid = '@aws-cdk/aws-eks.ClusterResourceProvider'; - return stack.construct.tryFindChild(uid) as ClusterResourceProvider || new ClusterResourceProvider(stack, uid); + return stack.node.tryFindChild(uid) as ClusterResourceProvider || new ClusterResourceProvider(stack, uid); } /** diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts index c6f037c075140..c885feaa476d2 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts @@ -162,7 +162,7 @@ export class ClusterResource extends Construct { }, }); - resource.construct.addDependency(this.creationRole); + resource.node.addDependency(this.creationRole); this.ref = resource.ref; this.attrEndpoint = Token.asString(resource.getAtt('Endpoint')); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index 65d24f12101be..dbc34c53353af 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -637,7 +637,7 @@ export class Cluster extends Resource implements ICluster { // the security group and vpc must exist in order to properly delete the cluster (since we run `kubectl delete`). // this ensures that. - this._clusterResource.construct.addDependency(this.kubctlProviderSecurityGroup, this.vpc); + this._clusterResource.node.addDependency(this.kubctlProviderSecurityGroup, this.vpc); // see https://github.com/aws/aws-cdk/issues/9027 this._clusterResource.creationRole.addToPolicy(new iam.PolicyStatement({ @@ -659,7 +659,7 @@ export class Cluster extends Resource implements ICluster { }); // add the cluster resource itself as a dependency of the barrier - this._kubectlReadyBarrier.construct.addDependency(this._clusterResource); + this._kubectlReadyBarrier.node.addDependency(this._clusterResource); this.clusterName = this.getResourceNameAttribute(resource.ref); this.clusterArn = this.getResourceArnAttribute(resource.attrArn, clusterArnComponents(this.physicalName)); @@ -988,7 +988,7 @@ export class Cluster extends Resource implements ICluster { // add all profiles as a dependency of the "kubectl-ready" barrier because all kubectl- // resources can only be deployed after all fargate profiles are created. if (this._kubectlReadyBarrier) { - this._kubectlReadyBarrier.construct.addDependency(fargateProfile); + this._kubectlReadyBarrier.node.addDependency(fargateProfile); } return this._fargateProfiles; @@ -1009,7 +1009,7 @@ export class Cluster extends Resource implements ICluster { const uid = '@aws-cdk/aws-eks.KubectlProvider'; // singleton - let provider = this.stack.construct.tryFindChild(uid) as KubectlProvider; + let provider = this.stack.node.tryFindChild(uid) as KubectlProvider; if (!provider) { // create the provider. @@ -1046,7 +1046,7 @@ export class Cluster extends Resource implements ICluster { throw new Error('unexpected: kubectl enabled clusters should have a kubectl-ready barrier resource'); } - resourceScope.construct.addDependency(this._kubectlReadyBarrier); + resourceScope.node.addDependency(this._kubectlReadyBarrier); return provider; } @@ -1130,11 +1130,11 @@ export class Cluster extends Resource implements ICluster { // message (if token): "could not auto-tag public/private subnet with tag..." // message (if not token): "count not auto-tag public/private subnet xxxxx with tag..." const subnetID = Token.isUnresolved(subnet.subnetId) ? '' : ` ${subnet.subnetId}`; - this.construct.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); + this.node.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); continue; } - subnet.construct.applyAspect(new Tag(tag, '1')); + subnet.node.applyAspect(new Tag(tag, '1')); } }; diff --git a/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts b/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts index bef0ce6cf6bfc..428d96ae24b36 100644 --- a/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts +++ b/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts @@ -189,7 +189,7 @@ export class FargateProfile extends Construct implements ITaggable { const clusterFargateProfiles = props.cluster._attachFargateProfile(this); if (clusterFargateProfiles.length > 1) { const previousProfile = clusterFargateProfiles[clusterFargateProfiles.length - 2]; - resource.construct.addDependency(previousProfile); + resource.node.addDependency(previousProfile); } // map the fargate pod execution role to the relevant groups in rbac diff --git a/packages/@aws-cdk/aws-eks/lib/helm-chart.ts b/packages/@aws-cdk/aws-eks/lib/helm-chart.ts index 5207b94ea4ba8..b46f0f8bbe09d 100644 --- a/packages/@aws-cdk/aws-eks/lib/helm-chart.ts +++ b/packages/@aws-cdk/aws-eks/lib/helm-chart.ts @@ -107,7 +107,7 @@ export class HelmChart extends Construct { properties: { ClusterName: props.cluster.clusterName, RoleArn: props.cluster._kubectlCreationRole.roleArn, - Release: props.release ?? this.construct.uniqueId.slice(-53).toLowerCase(), // Helm has a 53 character limit for the name + Release: props.release ?? this.node.uniqueId.slice(-53).toLowerCase(), // Helm has a 53 character limit for the name Chart: props.chart, Version: props.version, Wait: wait || undefined, // props are stringified so we encode “false” as undefined diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-layer.ts b/packages/@aws-cdk/aws-eks/lib/kubectl-layer.ts index fc2710c13b401..84efa5325854a 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-layer.ts +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-layer.ts @@ -29,7 +29,7 @@ export class KubectlLayer extends Construct implements lambda.ILayerVersion { public static getOrCreate(scope: Construct, props: KubectlLayerProps = {}): KubectlLayer { const stack = Stack.of(scope); const id = 'kubectl-layer-' + (props.version ? props.version : '8C2542BC-BF2B-4DFE-B765-E181FD30A9A0'); - const exists = stack.construct.tryFindChild(id) as KubectlLayer; + const exists = stack.node.tryFindChild(id) as KubectlLayer; if (exists) { return exists; } @@ -50,7 +50,7 @@ export class KubectlLayer extends Construct implements lambda.ILayerVersion { constructor(scope: Construct, id: string, props: KubectlLayerProps = {}) { super(scope, id); - const uniqueId = crypto.createHash('md5').update(this.construct.path).digest('hex'); + const uniqueId = crypto.createHash('md5').update(this.node.path).digest('hex'); const version = props.version || KUBECTL_APP_VERSION; this.stack.templateOptions.transforms = [ 'AWS::Serverless-2016-10-31' ]; // required for AWS::Serverless diff --git a/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts b/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts index f9dca4ace1bb7..3e2ba0feb9abd 100644 --- a/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts @@ -361,11 +361,11 @@ export class LegacyCluster extends Resource implements ICluster { // message (if token): "could not auto-tag public/private subnet with tag..." // message (if not token): "count not auto-tag public/private subnet xxxxx with tag..." const subnetID = Token.isUnresolved(subnet.subnetId) ? '' : ` ${subnet.subnetId}`; - this.construct.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); + this.node.addWarning(`Could not auto-tag ${type} subnet${subnetID} with "${tag}=1", please remember to do this manually`); continue; } - subnet.construct.applyAspect(new Tag(tag, '1')); + subnet.node.applyAspect(new Tag(tag, '1')); } }; diff --git a/packages/@aws-cdk/aws-eks/lib/service-account.ts b/packages/@aws-cdk/aws-eks/lib/service-account.ts index 665f6418b5278..83da66fbfef73 100644 --- a/packages/@aws-cdk/aws-eks/lib/service-account.ts +++ b/packages/@aws-cdk/aws-eks/lib/service-account.ts @@ -57,7 +57,7 @@ export class ServiceAccount extends Construct implements IPrincipal { super(scope, id); const { cluster } = props; - this.serviceAccountName = props.name ?? this.construct.uniqueId.toLowerCase(); + this.serviceAccountName = props.name ?? this.node.uniqueId.toLowerCase(); this.serviceAccountNamespace = props.namespace ?? 'default'; /* Add conditions to the role to improve security. This prevents other pods in the same namespace to assume the role. diff --git a/packages/@aws-cdk/aws-eks/lib/user-data.ts b/packages/@aws-cdk/aws-eks/lib/user-data.ts index 5cad1fc2a57df..cf38cf7ee9761 100644 --- a/packages/@aws-cdk/aws-eks/lib/user-data.ts +++ b/packages/@aws-cdk/aws-eks/lib/user-data.ts @@ -8,7 +8,7 @@ export function renderAmazonLinuxUserData(clusterName: string, autoScalingGroup: const stack = Stack.of(autoScalingGroup); // determine logical id of ASG so we can signal cloudformation - const cfn = autoScalingGroup.construct.defaultChild as autoscaling.CfnAutoScalingGroup; + const cfn = autoScalingGroup.node.defaultChild as autoscaling.CfnAutoScalingGroup; const asgLogicalId = cfn.logicalId; const extraArgs = new Array(); diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts index 38b9ab11dc606..6340be221a298 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.ts @@ -99,7 +99,7 @@ class EksClusterStack extends TestStack { }); // make sure namespace is deployed before the chart - nginxIngress.construct.addDependency(nginxNamespace); + nginxIngress.node.addDependency(nginxNamespace); // add a service account connected to a IAM role cluster.addServiceAccount('MyServiceAccount'); diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 19d05afb89853..576e4081e83c0 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -1386,7 +1386,7 @@ export = { }); // the kubectl provider is inside a nested stack. - const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; expect(nested).to(haveResource('AWS::Lambda::Function', { Environment: { Variables: { @@ -1427,7 +1427,7 @@ export = { region: 'us-east-1', }, }); - stack.construct.setContext(`vpc-provider:account=${stack.account}:filter.vpc-id=${vpcId}:region=${stack.region}:returnAsymmetricSubnets=true`, { + stack.node.setContext(`vpc-provider:account=${stack.account}:filter.vpc-id=${vpcId}:region=${stack.region}:returnAsymmetricSubnets=true`, { vpcId: vpcId, vpcCidrBlock: '10.0.0.0/16', subnetGroups: [ @@ -1467,7 +1467,7 @@ export = { endpointAccess: eks.EndpointAccess.PRIVATE, }); - const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; const template = expect(nested).value; test.deepEqual(template.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds, [ @@ -1488,7 +1488,7 @@ export = { })]}], }); - const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; const template = expect(nested).value; test.deepEqual(template.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds, [ @@ -1588,7 +1588,7 @@ export = { }); // the kubectl provider is inside a nested stack. - const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; expect(nested).to(haveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ @@ -1652,7 +1652,7 @@ export = { }); // the kubectl provider is inside a nested stack. - const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; test.equal(16, expect(nested).value.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds.length); test.done(); @@ -1701,7 +1701,7 @@ export = { }); // the kubectl provider is inside a nested stack. - const nested = stack.construct.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; + const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack; expect(nested).to(haveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts index 3e8096a61d297..d4c36abe15221 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts @@ -248,7 +248,7 @@ export class LoadBalancer extends Resource implements IConnectable { crossZone: (props.crossZone === undefined || props.crossZone) ? true : false, }); if (props.internetFacing) { - this.elb.construct.addDependency(selectedSubnets.internetConnectivityEstablished); + this.elb.node.addDependency(selectedSubnets.internetConnectivityEstablished); } ifUndefined(props.listeners, []).forEach(b => this.addListener(b)); diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/test.loadbalancer.ts b/packages/@aws-cdk/aws-elasticloadbalancing/test/test.loadbalancer.ts index 550a21f520ec2..fdbfca95ae4eb 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/test.loadbalancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/test.loadbalancer.ts @@ -7,7 +7,7 @@ import { ILoadBalancerTarget, LoadBalancer, LoadBalancingProtocol } from '../lib export = { 'test specifying nonstandard port works'(test: Test) { const stack = new Stack(undefined, undefined, { env: { account: '1234', region: 'test' }}); - stack.construct.setContext('availability-zones:1234:test', ['test-1a', 'test-1b']); + stack.node.setContext('availability-zones:1234:test', ['test-1a', 'test-1b']); const vpc = new Vpc(stack, 'VCP'); const lb = new LoadBalancer(stack, 'LB', { vpc }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.ts index aa4172256a44e..f9ab2c015b382 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/test/integ.cognito.lit.ts @@ -44,7 +44,7 @@ class CognitoStack extends Stack { ], }, }); - const cfnClient = userPoolClient.construct.defaultChild as cognito.CfnUserPoolClient; + const cfnClient = userPoolClient.node.defaultChild as cognito.CfnUserPoolClient; cfnClient.addPropertyOverride('RefreshTokenValidity', 1); cfnClient.addPropertyOverride('SupportedIdentityProviders', ['COGNITO']); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts index 3234c5b249532..a8de884e9f2c0 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts @@ -298,7 +298,7 @@ export class ApplicationListenerRule extends cdk.Construct { // Instead, signal this through a warning. // @deprecate: upon the next major version bump, replace this with a `throw` if (this.action) { - this.construct.addWarning('An Action already existed on this ListenerRule and was replaced. Configure exactly one default Action.'); + this.node.addWarning('An Action already existed on this ListenerRule and was replaced. Configure exactly one default Action.'); } action.bind(this, this.listener, this); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts index be195010d03bf..a9e469394b8c3 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts @@ -69,7 +69,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic this.ipAddressType = props.ipAddressType ?? IpAddressType.IPV4; this.securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, - description: `Automatically created Security Group for ELB ${this.construct.uniqueId}`, + description: `Automatically created Security Group for ELB ${this.node.uniqueId}`, allowAllOutbound: false, }); this.connections = new ec2.Connections({ securityGroups: [this.securityGroup] }); @@ -562,12 +562,12 @@ class ImportedApplicationLoadBalancer extends Resource implements IApplicationLo public get loadBalancerCanonicalHostedZoneId(): string { if (this.props.loadBalancerCanonicalHostedZoneId) { return this.props.loadBalancerCanonicalHostedZoneId; } // eslint-disable-next-line max-len - throw new Error(`'loadBalancerCanonicalHostedZoneId' was not provided when constructing Application Load Balancer ${this.construct.path} from attributes`); + throw new Error(`'loadBalancerCanonicalHostedZoneId' was not provided when constructing Application Load Balancer ${this.node.path} from attributes`); } public get loadBalancerDnsName(): string { if (this.props.loadBalancerDnsName) { return this.props.loadBalancerDnsName; } // eslint-disable-next-line max-len - throw new Error(`'loadBalancerDnsName' was not provided when constructing Application Load Balancer ${this.construct.path} from attributes`); + throw new Error(`'loadBalancerDnsName' was not provided when constructing Application Load Balancer ${this.node.path} from attributes`); } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 66e251538ff39..9d6561356f5e9 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -374,11 +374,11 @@ export interface IApplicationTargetGroup extends ITargetGroup { class ImportedApplicationTargetGroup extends ImportedTargetGroupBase implements IApplicationTargetGroup { public registerListener(_listener: IApplicationListener, _associatingConstruct?: IConstruct) { // Nothing to do, we know nothing of our members - this.construct.addWarning('Cannot register listener on imported target group -- security groups might need to be updated manually'); + this.node.addWarning('Cannot register listener on imported target group -- security groups might need to be updated manually'); } public registerConnectable(_connectable: ec2.IConnectable, _portRange?: ec2.Port | undefined): void { - this.construct.addWarning('Cannot register connectable on imported target group -- security groups might need to be updated manually'); + this.node.addWarning('Cannot register connectable on imported target group -- security groups might need to be updated manually'); } public addTarget(...targets: IApplicationLoadBalancerTarget[]) { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts index 4c197a6b71347..28e23cc56a257 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts @@ -70,13 +70,13 @@ export class NetworkLoadBalancer extends BaseLoadBalancer implements INetworkLoa public get loadBalancerCanonicalHostedZoneId(): string { if (attrs.loadBalancerCanonicalHostedZoneId) { return attrs.loadBalancerCanonicalHostedZoneId; } // eslint-disable-next-line max-len - throw new Error(`'loadBalancerCanonicalHostedZoneId' was not provided when constructing Network Load Balancer ${this.construct.path} from attributes`); + throw new Error(`'loadBalancerCanonicalHostedZoneId' was not provided when constructing Network Load Balancer ${this.node.path} from attributes`); } public get loadBalancerDnsName(): string { if (attrs.loadBalancerDnsName) { return attrs.loadBalancerDnsName; } // eslint-disable-next-line max-len - throw new Error(`'loadBalancerDnsName' was not provided when constructing Network Load Balancer ${this.construct.path} from attributes`); + throw new Error(`'loadBalancerDnsName' was not provided when constructing Network Load Balancer ${this.node.path} from attributes`); } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts index 767af7db4eb66..d9405bff1f729 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts @@ -50,7 +50,7 @@ export abstract class BaseListener extends Resource { // Instead, signal this through a warning. // @deprecate: upon the next major version bump, replace this with a `throw` if (this.defaultAction) { - this.construct.addWarning('A default Action already existed on this Listener and was replaced. Configure exactly one default Action.'); + this.node.addWarning('A default Action already existed on this Listener and was replaced. Configure exactly one default Action.'); } this.defaultAction = action; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts index 6e6693b3081db..7c7447d19eba0 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts @@ -142,7 +142,7 @@ export abstract class BaseLoadBalancer extends Resource { ...additionalProps, }); if (internetFacing) { - resource.construct.addDependency(internetConnectivityEstablished); + resource.node.addDependency(internetConnectivityEstablished); } if (baseProps.deletionProtection) { this.setAttribute('deletion_protection.enabled', 'true'); } @@ -180,7 +180,7 @@ export abstract class BaseLoadBalancer extends Resource { bucket.grantPut(new iam.AccountPrincipal(account), `${(prefix ? prefix + '/' : '')}AWSLogs/${Stack.of(this).account}/*`); // make sure the bucket's policy is created before the ALB (see https://github.com/aws/aws-cdk/issues/1633) - this.construct.addDependency(bucket); + this.node.addDependency(bucket); } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index affdbc2b8f5bd..f35642e6d4c9e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -313,7 +313,7 @@ export abstract class TargetGroupBase extends cdk.Construct implements ITargetGr const ret = super.validate(); if (this.targetType === undefined && this.targetsJson.length === 0) { - this.construct.addWarning("When creating an empty TargetGroup, you should specify a 'targetType' (this warning may become an error in the future)."); + this.node.addWarning("When creating an empty TargetGroup, you should specify a 'targetType' (this warning may become an error in the future)."); } if (this.targetType !== TargetType.LAMBDA && this.vpc === undefined) { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts index 86cec342bd85f..188fd80ea4eea 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.listener.ts @@ -1359,6 +1359,6 @@ export = { class ResourceWithLBDependency extends cdk.CfnResource { constructor(scope: cdk.Construct, id: string, targetGroup: elbv2.ITargetGroup) { super(scope, id, { type: 'Test::Resource' }); - this.construct.addDependency(targetGroup.loadBalancerAttached); + this.node.addDependency(targetGroup.loadBalancerAttached); } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts index 53778415690d5..5ce09e6f82ef3 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb.dualstack.ts @@ -38,7 +38,7 @@ const ipv6Block = new ec2.CfnVPCCidrBlock( // Get the vpc's internet gateway so we can create default routes for the // public subnets. const internetGateway = valueOrDie( - vpc.construct.children.find(c => c instanceof ec2.CfnInternetGateway), + vpc.node.children.find(c => c instanceof ec2.CfnInternetGateway), new Error('Couldnt find an internet gateway'), ); @@ -54,7 +54,7 @@ vpc.publicSubnets.forEach((subnet, idx) => { // Find a CfnSubnet (raw cloudformation resources) child to the public // subnet nodes. const cfnSubnet = valueOrDie( - subnet.construct.children.find(c => c instanceof ec2.CfnSubnet), + subnet.node.children.find(c => c instanceof ec2.CfnSubnet), new Error('Couldnt find a CfnSubnet'), ); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.ts index b3fac7df3efae..2b6ad8cff5c90 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.nlb.ts @@ -24,7 +24,7 @@ const group = listener.addTargets('Target', { targets: [new elbv2.IpTarget('10.0.1.1')], }); -group.construct.addDependency(vpc.internetConnectivityEstablished); +group.node.addDependency(vpc.internetConnectivityEstablished); // The target's security group must allow being routed by the LB and the clients. diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/test.listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/test.listener.ts index 16eba5fb4766e..a94421e357154 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/test.listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/test.listener.ts @@ -339,6 +339,6 @@ export = { class ResourceWithLBDependency extends cdk.CfnResource { constructor(scope: cdk.Construct, id: string, targetGroup: elbv2.ITargetGroup) { super(scope, id, { type: 'Test::Resource' }); - this.construct.addDependency(targetGroup.loadBalancerAttached); + this.node.addDependency(targetGroup.loadBalancerAttached); } } diff --git a/packages/@aws-cdk/aws-events-targets/lib/aws-api.ts b/packages/@aws-cdk/aws-events-targets/lib/aws-api.ts index b40ae306d106a..9eade462aae13 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/aws-api.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/aws-api.ts @@ -81,7 +81,7 @@ export class AwsApi implements events.IRuleTarget { * result from an EventBridge event. */ public bind(rule: events.IRule, id?: string): events.RuleTargetConfig { - const handler = new lambda.SingletonFunction(rule as events.Rule, `${rule.construct.id}${id}Handler`, { + const handler = new lambda.SingletonFunction(rule as events.Rule, `${rule.node.id}${id}Handler`, { code: lambda.Code.fromAsset(path.join(__dirname, 'aws-api-handler')), runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', diff --git a/packages/@aws-cdk/aws-events-targets/lib/batch.ts b/packages/@aws-cdk/aws-events-targets/lib/batch.ts index 2e45b693137fd..69f9a52fdbb35 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/batch.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/batch.ts @@ -59,7 +59,7 @@ export class BatchJob implements events.IRuleTarget { public bind(rule: events.IRule, _id?: string): events.RuleTargetConfig { const batchParameters: events.CfnRule.BatchParametersProperty = { jobDefinition: this.jobDefinition.jobDefinitionArn, - jobName: this.props.jobName ?? rule.construct.uniqueId, + jobName: this.props.jobName ?? rule.node.uniqueId, arrayProperties: this.props.size ? { size: this.props.size } : undefined, retryStrategy: this.props.attempts ? { attempts: this.props.attempts } : undefined, }; diff --git a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts index 7c48c4ce8216d..77fdae5d37208 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/ecs-task.ts @@ -115,7 +115,7 @@ export class EcsTask implements events.IRuleTarget { // Security groups are only configurable with the "awsvpc" network mode. if (this.taskDefinition.networkMode !== ecs.NetworkMode.AWS_VPC) { if (props.securityGroup !== undefined || props.securityGroups !== undefined) { - this.taskDefinition.construct.addWarning('security groups are ignored when network mode is not awsvpc'); + this.taskDefinition.node.addWarning('security groups are ignored when network mode is not awsvpc'); } return; } @@ -123,7 +123,7 @@ export class EcsTask implements events.IRuleTarget { this.securityGroups = props.securityGroups; return; } - let securityGroup = props.securityGroup || this.taskDefinition.construct.tryFindChild('SecurityGroup') as ec2.ISecurityGroup; + let securityGroup = props.securityGroup || this.taskDefinition.node.tryFindChild('SecurityGroup') as ec2.ISecurityGroup; securityGroup = securityGroup || new ec2.SecurityGroup(this.taskDefinition, 'SecurityGroup', { vpc: this.props.cluster.vpc }); this.securityGroup = securityGroup; // Maintain backwards-compatibility for customers that read the generated security group. this.securityGroups = [securityGroup]; diff --git a/packages/@aws-cdk/aws-events-targets/lib/util.ts b/packages/@aws-cdk/aws-events-targets/lib/util.ts index a116aab8849cd..ddcd83adb5f1b 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/util.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/util.ts @@ -11,7 +11,7 @@ import { Construct, IConstruct } from '@aws-cdk/core'; */ export function singletonEventRole(scope: IConstruct, policyStatements: iam.PolicyStatement[]): iam.IRole { const id = 'EventsRole'; - const existing = scope.construct.tryFindChild(id) as iam.IRole; + const existing = scope.node.tryFindChild(id) as iam.IRole; if (existing) { return existing; } const role = new iam.Role(scope as Construct, id, { @@ -27,7 +27,7 @@ export function singletonEventRole(scope: IConstruct, policyStatements: iam.Poli * Allows a Lambda function to be called from a rule */ export function addLambdaPermission(rule: events.IRule, handler: lambda.IFunction): void { - const permissionId = `AllowEventRule${rule.construct.uniqueId}`; + const permissionId = `AllowEventRule${rule.node.uniqueId}`; if (!handler.permissionsNode.tryFindChild(permissionId)) { handler.addPermission(permissionId, { action: 'lambda:InvokeFunction', diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts b/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts index 7a3ff8a30e1a7..3e2b5e524ba3b 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/pipeline.test.ts @@ -95,7 +95,7 @@ describe('CodePipeline event target', () => { const role = new iam.Role(stack, 'MyExampleRole', { assumedBy: new iam.AnyPrincipal(), }); - const roleResource = role.construct.defaultChild as CfnElement; + const roleResource = role.node.defaultChild as CfnElement; roleResource.overrideLogicalId('MyRole'); // to make it deterministic in the assertion below rule.addTarget(new targets.CodePipeline(pipeline, { diff --git a/packages/@aws-cdk/aws-events/lib/event-bus.ts b/packages/@aws-cdk/aws-events/lib/event-bus.ts index 1697cec293e1a..366c259685527 100644 --- a/packages/@aws-cdk/aws-events/lib/event-bus.ts +++ b/packages/@aws-cdk/aws-events/lib/event-bus.ts @@ -218,7 +218,7 @@ export class EventBus extends Resource implements IEventBus { constructor(scope: Construct, id: string, props?: EventBusProps) { const { eventBusName, eventSourceName } = EventBus.eventBusProps( - Lazy.stringValue({ produce: () => this.construct.uniqueId }), + Lazy.stringValue({ produce: () => this.node.uniqueId }), props, ); diff --git a/packages/@aws-cdk/aws-events/lib/rule.ts b/packages/@aws-cdk/aws-events/lib/rule.ts index a7d630087ce48..1b19b5f1174a9 100644 --- a/packages/@aws-cdk/aws-events/lib/rule.ts +++ b/packages/@aws-cdk/aws-events/lib/rule.ts @@ -221,11 +221,11 @@ export class Rule extends Resource implements IRule { // (EventBridge verifies whether you have permissions to the targets on rule creation), // but it's common for the target stack to depend on the source stack // (that's the case with CodePipeline, for example) - const sourceApp = this.construct.root; + const sourceApp = this.node.root; if (!sourceApp || !App.isApp(sourceApp)) { throw new Error('Event stack which uses cross-account targets must be part of a CDK app'); } - const targetApp = targetProps.targetResource.construct.root; + const targetApp = targetProps.targetResource.node.root; if (!targetApp || !App.isApp(targetApp)) { throw new Error('Target stack which uses cross-account event targets must be part of a CDK app'); } @@ -233,7 +233,7 @@ export class Rule extends Resource implements IRule { throw new Error('Event stack and target stack must belong to the same CDK app'); } const stackId = `EventBusPolicy-${sourceAccount}-${targetRegion}-${targetAccount}`; - let eventBusPolicyStack: Stack = sourceApp.construct.tryFindChild(stackId) as Stack; + let eventBusPolicyStack: Stack = sourceApp.node.tryFindChild(stackId) as Stack; if (!eventBusPolicyStack) { eventBusPolicyStack = new Stack(sourceApp, stackId, { env: { @@ -275,7 +275,7 @@ export class Rule extends Resource implements IRule { } } - new CopyRule(targetStack, `${this.construct.uniqueId}-${id}`, { + new CopyRule(targetStack, `${this.node.uniqueId}-${id}`, { targets: [target], eventPattern: this.eventPattern, schedule: this.scheduleExpression ? Schedule.expression(this.scheduleExpression) : undefined, diff --git a/packages/@aws-cdk/aws-events/test/test.rule.ts b/packages/@aws-cdk/aws-events/test/test.rule.ts index a6c9cc106e475..e6ae493b60ab7 100644 --- a/packages/@aws-cdk/aws-events/test/test.rule.ts +++ b/packages/@aws-cdk/aws-events/test/test.rule.ts @@ -361,7 +361,7 @@ export = { const t1: IRuleTarget = { bind: (eventRule: IRule) => { receivedRuleArn = eventRule.ruleArn; - receivedRuleId = eventRule.construct.uniqueId; + receivedRuleId = eventRule.node.uniqueId; return { id: '', @@ -375,7 +375,7 @@ export = { rule.addTarget(t1); test.deepEqual(stack.resolve(receivedRuleArn), stack.resolve(rule.ruleArn)); - test.deepEqual(receivedRuleId, rule.construct.uniqueId); + test.deepEqual(receivedRuleId, rule.node.uniqueId); test.done(); }, @@ -678,7 +678,7 @@ export = { ], })); - const eventBusPolicyStack = app.construct.findChild(`EventBusPolicy-${sourceAccount}-us-west-2-${targetAccount}`) as cdk.Stack; + const eventBusPolicyStack = app.node.findChild(`EventBusPolicy-${sourceAccount}-us-west-2-${targetAccount}`) as cdk.Stack; expect(eventBusPolicyStack).to(haveResourceLike('AWS::Events::EventBusPolicy', { 'Action': 'events:PutEvents', 'StatementId': `Allow-account-${sourceAccount}`, diff --git a/packages/@aws-cdk/aws-glue/lib/table.ts b/packages/@aws-cdk/aws-glue/lib/table.ts index c8a13826295d4..3ed844d2d600a 100644 --- a/packages/@aws-cdk/aws-glue/lib/table.ts +++ b/packages/@aws-cdk/aws-glue/lib/table.ts @@ -284,7 +284,7 @@ export class Table extends Resource implements ITable { resource: 'table', resourceName: `${this.database.databaseName}/${this.tableName}`, }); - this.construct.defaultChild = tableResource; + this.node.defaultChild = tableResource; } /** diff --git a/packages/@aws-cdk/aws-glue/test/table.test.ts b/packages/@aws-cdk/aws-glue/test/table.test.ts index 5989bd075120d..a35d48e3d93dd 100644 --- a/packages/@aws-cdk/aws-glue/test/table.test.ts +++ b/packages/@aws-cdk/aws-glue/test/table.test.ts @@ -220,7 +220,7 @@ test('compressed table', () => { }); -test('table.construct.defaultChild', () => { +test('table.node.defaultChild', () => { // GIVEN const stack = new cdk.Stack(); const database = new glue.Database(stack, 'Database', { @@ -240,7 +240,7 @@ test('table.construct.defaultChild', () => { }); // THEN - ok(table.construct.defaultChild instanceof glue.CfnTable); + ok(table.node.defaultChild instanceof glue.CfnTable); }); test('encrypted table: SSE-S3', () => { diff --git a/packages/@aws-cdk/aws-iam/lib/grant.ts b/packages/@aws-cdk/aws-iam/lib/grant.ts index d533ea2c3902d..c0cb065f7ee2c 100644 --- a/packages/@aws-cdk/aws-iam/lib/grant.ts +++ b/packages/@aws-cdk/aws-iam/lib/grant.ts @@ -263,11 +263,11 @@ export class Grant implements cdk.IDependable { /** * Make sure this grant is applied before the given constructs are deployed * - * The same as construct.construct.addDependency(grant), but slightly nicer to read. + * The same as construct.node.addDependency(grant), but slightly nicer to read. */ public applyBefore(...constructs: cdk.IConstruct[]) { for (const construct of constructs) { - construct.construct.addDependency(this); + construct.node.addDependency(this); } } } diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index dd5855242bb7e..23cde93dc101c 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -417,7 +417,7 @@ export class Role extends Resource implements IRole { */ public withoutPolicyUpdates(): IRole { if (!this.immutableRole) { - this.immutableRole = new ImmutableRole(this.construct.scope as Construct, `ImmutableRole${this.construct.id}`, this); + this.immutableRole = new ImmutableRole(this.node.scope as Construct, `ImmutableRole${this.node.id}`, this); } return this.immutableRole; diff --git a/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts b/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts index 2486ff9f9bd60..da30dbf08227e 100644 --- a/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts +++ b/packages/@aws-cdk/aws-iam/lib/unknown-principal.ts @@ -34,13 +34,13 @@ export class UnknownPrincipal implements IPrincipal { } public get policyFragment(): PrincipalPolicyFragment { - throw new Error(`Cannot get policy fragment of ${this.resource.construct.path}, resource imported without a role`); + throw new Error(`Cannot get policy fragment of ${this.resource.node.path}, resource imported without a role`); } public addToPrincipalPolicy(statement: PolicyStatement): AddToPrincipalPolicyResult { const stack = Stack.of(this.resource); const repr = JSON.stringify(stack.resolve(statement)); - this.resource.construct.addWarning(`Add statement to this resource's role: ${repr}`); + this.resource.node.addWarning(`Add statement to this resource's role: ${repr}`); // Pretend we did the work. The human will do it for us, eventually. return { statementAdded: true, policyDependable: new ConcreteDependable() }; } diff --git a/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts b/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts index 847120c86d05b..4aa2ce2e9ddb8 100644 --- a/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts +++ b/packages/@aws-cdk/aws-iam/test/escape-hatch.test.ts @@ -14,7 +14,7 @@ describe('IAM escape hatches', () => { userName: 'MyUserName', }); - const cfn = user.construct.findChild('Resource') as iam.CfnUser; + const cfn = user.node.findChild('Resource') as iam.CfnUser; cfn.addPropertyOverride('UserName', 'OverriddenUserName'); expect(stack).toMatchTemplate({ @@ -33,7 +33,7 @@ describe('IAM escape hatches', () => { // GIVEN const stack = new Stack(); const user = new iam.User(stack, 'user', { userName: 'MyUserName' }); - const cfn = user.construct.findChild('Resource') as iam.CfnUser; + const cfn = user.node.findChild('Resource') as iam.CfnUser; // WHEN cfn.addPropertyOverride('Hello.World', 'Boom'); @@ -58,7 +58,7 @@ describe('IAM escape hatches', () => { // GIVEN const stack = new Stack(); const user = new iam.User(stack, 'user', { userName: 'MyUserName' }); - const cfn = user.construct.findChild('Resource') as iam.CfnUser; + const cfn = user.node.findChild('Resource') as iam.CfnUser; cfn.cfnOptions.updatePolicy = { useOnlineResharding: true }; // WHEN diff --git a/packages/@aws-cdk/aws-iam/test/policy.test.ts b/packages/@aws-cdk/aws-iam/test/policy.test.ts index 9c85bf9d7e56c..5bd50db9fd64f 100644 --- a/packages/@aws-cdk/aws-iam/test/policy.test.ts +++ b/packages/@aws-cdk/aws-iam/test/policy.test.ts @@ -262,7 +262,7 @@ describe('IAM policy', () => { }); // WHEN - res.construct.addDependency(pol); + res.node.addDependency(pol); // THEN expect(stack).toMatchTemplate({ @@ -288,7 +288,7 @@ describe('IAM policy', () => { }); // WHEN - res.construct.addDependency(pol); + res.node.addDependency(pol); // THEN expect(stack).toHaveResource('Some::Resource', { @@ -325,7 +325,7 @@ describe('IAM policy', () => { function createPolicyWithLogicalId(stack: Stack, logicalId: string): void { const policy = new Policy(stack, logicalId); - const cfnPolicy = policy.construct.defaultChild as CfnPolicy; + const cfnPolicy = policy.node.defaultChild as CfnPolicy; cfnPolicy.overrideLogicalId(logicalId); // force a particular logical ID // add statements & principal to satisfy validation diff --git a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts index 5a18d395ac32f..295cae174fe6a 100644 --- a/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts +++ b/packages/@aws-cdk/aws-iam/test/role.from-role-arn.test.ts @@ -535,7 +535,7 @@ function somePolicy(policyStack: Stack, policyName: string) { const someRole = new Role(policyStack, 'SomeExampleRole', { assumedBy: new AnyPrincipal(), }); - const roleResource = someRole.construct.defaultChild as CfnElement; + const roleResource = someRole.node.defaultChild as CfnElement; roleResource.overrideLogicalId('SomeRole'); // force a particular logical ID in the Ref expression return new Policy(policyStack, 'MyPolicy', { diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index ce53655e4abf0..31650f4c9da63 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -299,7 +299,7 @@ export class Stream extends StreamBase { if (!props.encryption && !props.encryptionKey) { const conditionName = 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions'; - const existing = Stack.of(this).construct.tryFindChild(conditionName); + const existing = Stack.of(this).node.tryFindChild(conditionName); // create a single condition for the Stack if (!existing) { @@ -338,7 +338,7 @@ export class Stream extends StreamBase { if (encryptionType === StreamEncryption.KMS) { const encryptionKey = props.encryptionKey || new kms.Key(this, 'Key', { - description: `Created by ${this.construct.path}`, + description: `Created by ${this.node.path}`, }); const streamEncryption: CfnStream.StreamEncryptionProperty = { diff --git a/packages/@aws-cdk/aws-kms/test/test.key.ts b/packages/@aws-cdk/aws-kms/test/test.key.ts index 56d33990415ba..a428ea1c05f73 100644 --- a/packages/@aws-cdk/aws-kms/test/test.key.ts +++ b/packages/@aws-cdk/aws-kms/test/test.key.ts @@ -160,9 +160,9 @@ export = { p.addArnPrincipal('arn'); key.addToResourcePolicy(p); - key.construct.applyAspect(new Tag('tag1', 'value1')); - key.construct.applyAspect(new Tag('tag2', 'value2')); - key.construct.applyAspect(new Tag('tag3', '')); + key.node.applyAspect(new Tag('tag1', 'value1')); + key.node.applyAspect(new Tag('tag2', 'value2')); + key.node.applyAspect(new Tag('tag3', '')); expect(stack).to(exactlyMatchTemplate({ Resources: { diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/api.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/api.ts index 98baa1d8fb472..2f3f3bcdc15fb 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/api.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/api.ts @@ -10,9 +10,9 @@ export class ApiEventSource implements lambda.IEventSource { } public bind(target: lambda.IFunction): void { - const id = `${target.construct.uniqueId}:ApiEventSourceA7A86A4F`; + const id = `${target.node.uniqueId}:ApiEventSourceA7A86A4F`; const stack = Stack.of(target); - let api = stack.construct.tryFindChild(id) as apigw.RestApi; + let api = stack.node.tryFindChild(id) as apigw.RestApi; if (!api) { api = new apigw.RestApi(stack, id, { defaultIntegration: new apigw.LambdaIntegration(target), diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts index c85ced6106ebf..ce9a3d8a5c998 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/dynamodb.ts @@ -21,10 +21,10 @@ export class DynamoEventSource extends StreamEventSource { public bind(target: lambda.IFunction) { if (!this.table.tableStreamArn) { - throw new Error(`DynamoDB Streams must be enabled on the table ${this.table.construct.path}`); + throw new Error(`DynamoDB Streams must be enabled on the table ${this.table.node.path}`); } - const eventSourceMapping = target.addEventSourceMapping(`DynamoDBEventSource:${this.table.construct.uniqueId}`, + const eventSourceMapping = target.addEventSourceMapping(`DynamoDBEventSource:${this.table.node.uniqueId}`, this.enrichMappingOptions({eventSourceArn: this.table.tableStreamArn}), ); this._eventSourceMappingId = eventSourceMapping.eventSourceMappingId; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/kinesis.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/kinesis.ts index dcfc8235e80eb..1a2de4c390155 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/kinesis.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/kinesis.ts @@ -23,7 +23,7 @@ export class KinesisEventSource extends StreamEventSource { } public bind(target: lambda.IFunction) { - const eventSourceMapping = target.addEventSourceMapping(`KinesisEventSource:${this.stream.construct.uniqueId}`, + const eventSourceMapping = target.addEventSourceMapping(`KinesisEventSource:${this.stream.node.uniqueId}`, this.enrichMappingOptions({eventSourceArn: this.stream.streamArn}), ); this._eventSourceMappingId = eventSourceMapping.eventSourceMappingId; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts index 148fd359a6295..9badef3e6f8bc 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts @@ -27,7 +27,7 @@ export class SqsEventSource implements lambda.IEventSource { } public bind(target: lambda.IFunction) { - const eventSourceMapping = target.addEventSourceMapping(`SqsEventSource:${this.queue.construct.uniqueId}`, { + const eventSourceMapping = target.addEventSourceMapping(`SqsEventSource:${this.queue.node.uniqueId}`, { batchSize: this.props.batchSize, eventSourceArn: this.queue.queueArn, }); diff --git a/packages/@aws-cdk/aws-lambda/lib/function-base.ts b/packages/@aws-cdk/aws-lambda/lib/function-base.ts index ea2b13454ad18..39ad7d665fcb7 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-base.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-base.ts @@ -287,7 +287,6 @@ export abstract class FunctionBase extends Resource implements IFunction { return { statementAdded: true, policyDependable: this._functionNode().findChild(identifier) } as iam.AddToResourcePolicyResult; }, node: this.node, - construct: this.construct, }, }); } @@ -309,8 +308,8 @@ export abstract class FunctionBase extends Resource implements IFunction { } public configureAsyncInvoke(options: EventInvokeConfigOptions): void { - if (this.construct.tryFindChild('EventInvokeConfig') !== undefined) { - throw new Error(`An EventInvokeConfig has already been configured for the function at ${this.construct.path}`); + if (this.node.tryFindChild('EventInvokeConfig') !== undefined) { + throw new Error(`An EventInvokeConfig has already been configured for the function at ${this.node.path}`); } new EventInvokeConfig(this, 'EventInvokeConfig', { @@ -368,8 +367,8 @@ export abstract class QualifiedFunctionBase extends FunctionBase { } public configureAsyncInvoke(options: EventInvokeConfigOptions): void { - if (this.construct.tryFindChild('EventInvokeConfig') !== undefined) { - throw new Error(`An EventInvokeConfig has already been configured for the qualified function at ${this.construct.path}`); + if (this.node.tryFindChild('EventInvokeConfig') !== undefined) { + throw new Error(`An EventInvokeConfig has already been configured for the qualified function at ${this.node.path}`); } new EventInvokeConfig(this, 'EventInvokeConfig', { diff --git a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts index e3e069e5fa7bc..fcc7cb4b75e2f 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function-hash.ts @@ -5,7 +5,7 @@ import { Function as LambdaFunction } from './function'; export function calculateFunctionHash(fn: LambdaFunction) { const stack = Stack.of(fn); - const functionResource = fn.construct.defaultChild as CfnResource; + const functionResource = fn.node.defaultChild as CfnResource; // render the cloudformation resource from this function const config = stack.resolve((functionResource as any)._toCloudFormation()); diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index bee7d8287ce81..5d0fd05c00b17 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -344,7 +344,7 @@ export class Function extends FunctionBase { // override the version's logical ID with a lazy string which includes the // hash of the function itself, so a new version resource is created when // the function configuration changes. - const cfn = this._currentVersion.construct.defaultChild as CfnResource; + const cfn = this._currentVersion.node.defaultChild as CfnResource; const originalLogicalId = this.stack.resolve(cfn.logicalId) as string; cfn.overrideLogicalId(Lazy.stringValue({ produce: _ => { @@ -604,7 +604,7 @@ export class Function extends FunctionBase { reservedConcurrentExecutions: props.reservedConcurrentExecutions, }); - resource.construct.addDependency(this.role); + resource.node.addDependency(this.role); this.functionName = this.getResourceNameAttribute(resource.ref); this.functionArn = this.getResourceArnAttribute(resource.attrArn, { @@ -652,7 +652,7 @@ export class Function extends FunctionBase { if (props.filesystem) { const config = props.filesystem.config; if (config.dependency) { - this.construct.addDependency(...config.dependency); + this.node.addDependency(...config.dependency); } resource.addPropertyOverride('FileSystemConfigs', @@ -755,7 +755,7 @@ export class Function extends FunctionBase { logGroupName: `/aws/lambda/${this.functionName}`, retention: logs.RetentionDays.INFINITE, }); - this._logGroup = logs.LogGroup.fromLogGroupArn(this, `${this.construct.id}-LogGroup`, logretention.logGroupArn); + this._logGroup = logs.LogGroup.fromLogGroupArn(this, `${this.node.id}-LogGroup`, logretention.logGroupArn); } return this._logGroup; } @@ -814,7 +814,7 @@ export class Function extends FunctionBase { } else { const securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, - description: 'Automatic security group for Lambda Function ' + this.construct.uniqueId, + description: 'Automatic security group for Lambda Function ' + this.node.uniqueId, allowAllOutbound: props.allowAllOutbound, }); securityGroups = [securityGroup]; diff --git a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts index 379a1aac981f6..f8515dc84e841 100644 --- a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts @@ -70,7 +70,7 @@ export class SingletonFunction extends FunctionBase { * as a singleton across the stack. Use this method instead to declare dependencies. */ public addDependency(...up: cdk.IDependable[]) { - this.lambdaFunction.construct.addDependency(...up); + this.lambdaFunction.node.addDependency(...up); } /** @@ -78,7 +78,7 @@ export class SingletonFunction extends FunctionBase { * node.addDependency(). Use this method instead to declare this as a dependency of another construct. */ public dependOn(down: cdk.IConstruct) { - down.construct.addDependency(this.lambdaFunction); + down.node.addDependency(this.lambdaFunction); } /** @@ -91,7 +91,7 @@ export class SingletonFunction extends FunctionBase { private ensureLambda(props: SingletonFunctionProps): IFunction { const constructName = (props.lambdaPurpose || 'SingletonLambda') + slugify(props.uuid); - const existing = cdk.Stack.of(this).construct.tryFindChild(constructName); + const existing = cdk.Stack.of(this).node.tryFindChild(constructName); if (existing) { // Just assume this is true return existing as FunctionBase; diff --git a/packages/@aws-cdk/aws-lambda/test/test.code.ts b/packages/@aws-cdk/aws-lambda/test/test.code.ts index 408ec9d00ca79..354771c697a0c 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.code.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.code.ts @@ -62,7 +62,7 @@ export = { 'adds code asset metadata'(test: Test) { // GIVEN const stack = new cdk.Stack(); - stack.construct.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); + stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); const location = path.join(__dirname, 'my-lambda-handler'); diff --git a/packages/@aws-cdk/aws-lambda/test/test.layers.ts b/packages/@aws-cdk/aws-lambda/test/test.layers.ts index b12cab6465653..9a1b2664aa268 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.layers.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.layers.ts @@ -77,7 +77,7 @@ export = testCase({ 'asset metadata is added to the cloudformation resource'(test: Test) { // GIVEN const stack = new cdk.Stack(); - stack.construct.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); + stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); // WHEN new lambda.LayerVersion(stack, 'layer', { diff --git a/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts b/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts index 1ea3ef56dcfeb..e4f57f5d4b33f 100644 --- a/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts +++ b/packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts @@ -14,7 +14,7 @@ export class KinesisDestination implements logs.ILogSubscriptionDestination { // Following example from https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#DestinationKinesisExample // Create a role to be assumed by CWL that can write to this stream and pass itself. const id = 'CloudWatchLogsCanPutRecords'; - const role = scope.construct.tryFindChild(id) as iam.IRole || new iam.Role(scope, id, { + const role = scope.node.tryFindChild(id) as iam.IRole || new iam.Role(scope, id, { assumedBy: new iam.ServicePrincipal('logs.amazonaws.com'), }); this.stream.grantWrite(role); diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index de2a56950ece0..2318fb1d9762e 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -341,7 +341,7 @@ export class DatabaseCluster extends DatabaseClusterBase { // Cannot test whether the subnets are in different AZs, but at least we can test the amount. if (subnetIds.length < 2) { - this.construct.addError(`Cluster requires at least 2 subnets, got ${subnetIds.length}`); + this.node.addError(`Cluster requires at least 2 subnets, got ${subnetIds.length}`); } const subnetGroup = new CfnDBSubnetGroup(this, 'Subnets', { @@ -520,7 +520,7 @@ export class DatabaseCluster extends DatabaseClusterBase { // We must have a dependency on the NAT gateway provider here to create // things in the right order. - instance.construct.addDependency(internetConnected); + instance.node.addDependency(internetConnected); this.instanceIdentifiers.push(instance.ref); this.instanceEndpoints.push(new Endpoint(instance.attrEndpointAddress, portAttribute)); @@ -542,7 +542,7 @@ export class DatabaseCluster extends DatabaseClusterBase { } const id = 'RotationSingleUser'; - const existing = this.construct.tryFindChild(id); + const existing = this.node.tryFindChild(id); if (existing) { throw new Error('A single user rotation was already added to this cluster.'); } diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index 6550222ac538d..0890b26b705d2 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -503,12 +503,12 @@ abstract class DatabaseInstanceNew extends DatabaseInstanceBase implements IData const { subnetIds } = props.vpc.selectSubnets(props.vpcPlacement); const subnetGroup = new CfnDBSubnetGroup(this, 'SubnetGroup', { - dbSubnetGroupDescription: `Subnet group for ${this.construct.id} database`, + dbSubnetGroupDescription: `Subnet group for ${this.node.id} database`, subnetIds, }); const securityGroups = props.securityGroups || [new ec2.SecurityGroup(this, 'SecurityGroup', { - description: `Security group for ${this.construct.id} database`, + description: `Security group for ${this.node.id} database`, vpc: props.vpc, })]; @@ -704,7 +704,7 @@ abstract class DatabaseInstanceSource extends DatabaseInstanceNew implements IDa } const id = 'RotationSingleUser'; - const existing = this.construct.tryFindChild(id); + const existing = this.node.tryFindChild(id); if (existing) { throw new Error('A single user rotation was already added to this instance.'); } diff --git a/packages/@aws-cdk/aws-rds/lib/proxy.ts b/packages/@aws-cdk/aws-rds/lib/proxy.ts index 970ffcade1ac9..eff37a0b4307c 100644 --- a/packages/@aws-cdk/aws-rds/lib/proxy.ts +++ b/packages/@aws-cdk/aws-rds/lib/proxy.ts @@ -69,9 +69,9 @@ export class ProxyTarget { if (this.dbCluster && this.dbInstance) { throw new Error('Proxy cannot target both database cluster and database instance.'); } else if (this.dbCluster) { - engine = (this.dbCluster.construct.defaultChild as CfnDBCluster).engine; + engine = (this.dbCluster.node.defaultChild as CfnDBCluster).engine; } else if (this.dbInstance) { - engine = (this.dbInstance.construct.defaultChild as CfnDBInstance).engine; + engine = (this.dbInstance.node.defaultChild as CfnDBInstance).engine; } let engineFamily; diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster.ts b/packages/@aws-cdk/aws-rds/test/test.cluster.ts index da015de8a5862..85d2a6d2b75d4 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/test.cluster.ts @@ -1114,6 +1114,6 @@ export = { function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' }}); - stack.construct.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + stack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); return stack; } diff --git a/packages/@aws-cdk/aws-redshift/lib/cluster.ts b/packages/@aws-cdk/aws-redshift/lib/cluster.ts index 489047df1b067..48caa7aabf1db 100644 --- a/packages/@aws-cdk/aws-redshift/lib/cluster.ts +++ b/packages/@aws-cdk/aws-redshift/lib/cluster.ts @@ -505,7 +505,7 @@ export class Cluster extends ClusterBase { } const id = 'RotationSingleUser'; - const existing = this.construct.tryFindChild(id); + const existing = this.node.tryFindChild(id); if (existing) { throw new Error('A single user rotation was already added to this cluster.'); } diff --git a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts index 7984b6877e97f..385a2f53208b5 100644 --- a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts @@ -324,6 +324,6 @@ test('throws when trying to add single user rotation multiple times', () => { function testStack() { const stack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } }); - stack.construct.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); + stack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']); return stack; } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53-targets/lib/cloudfront-target.ts b/packages/@aws-cdk/aws-route53-targets/lib/cloudfront-target.ts index c78c599a0c492..217ba72cfc079 100644 --- a/packages/@aws-cdk/aws-route53-targets/lib/cloudfront-target.ts +++ b/packages/@aws-cdk/aws-route53-targets/lib/cloudfront-target.ts @@ -22,7 +22,7 @@ export class CloudFrontTarget implements route53.IAliasRecordTarget { const scopeStack = Stack.of(scope); let mapping = - (scopeStack.construct.tryFindChild(mappingName) as CfnMapping) ?? + (scopeStack.node.tryFindChild(mappingName) as CfnMapping) ?? new CfnMapping(scopeStack, mappingName, { mapping: { ['aws']: { diff --git a/packages/@aws-cdk/aws-route53-targets/lib/interface-vpc-endpoint-target.ts b/packages/@aws-cdk/aws-route53-targets/lib/interface-vpc-endpoint-target.ts index f01a8843bcf9e..40b0902cd236a 100644 --- a/packages/@aws-cdk/aws-route53-targets/lib/interface-vpc-endpoint-target.ts +++ b/packages/@aws-cdk/aws-route53-targets/lib/interface-vpc-endpoint-target.ts @@ -8,7 +8,7 @@ import * as cdk from '@aws-cdk/core'; export class InterfaceVpcEndpointTarget implements route53.IAliasRecordTarget { private readonly cfnVpcEndpoint: ec2.CfnVPCEndpoint; constructor(private readonly vpcEndpoint: ec2.IInterfaceVpcEndpoint) { - this.cfnVpcEndpoint = this.vpcEndpoint.construct.findChild('Resource') as ec2.CfnVPCEndpoint; + this.cfnVpcEndpoint = this.vpcEndpoint.node.findChild('Resource') as ec2.CfnVPCEndpoint; } public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig { diff --git a/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts b/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts index 93d28fe930bef..98778fe9d5107 100644 --- a/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts +++ b/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts @@ -32,7 +32,7 @@ export = { const stack2 = new cdk.Stack(undefined, 'TestStack', { env: { account: '12345', region: 'us-east-1' }, }); - stack2.construct.setContext(missing[0].key, fakeZone); + stack2.node.setContext(missing[0].key, fakeZone); // WHEN const zoneRef = HostedZone.fromLookup(stack2, 'MyZoneProvider', filter); @@ -70,7 +70,7 @@ export = { const stack2 = new cdk.Stack(undefined, 'TestStack', { env: { account: '12345', region: 'us-east-1' }, }); - stack2.construct.setContext(missing[0].key, fakeZone); + stack2.node.setContext(missing[0].key, fakeZone); const zone = HostedZone.fromLookup(stack2, 'MyZoneProvider', filter); diff --git a/packages/@aws-cdk/aws-route53/test/test.util.ts b/packages/@aws-cdk/aws-route53/test/test.util.ts index 6afb828aae570..006527d3ad869 100644 --- a/packages/@aws-cdk/aws-route53/test/test.util.ts +++ b/packages/@aws-cdk/aws-route53/test/test.util.ts @@ -26,7 +26,6 @@ export = { hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', stack, node: stack.node, - construct: stack.construct, }); // THEN @@ -46,7 +45,6 @@ export = { hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', stack, node: stack.node, - construct: stack.construct, }); // THEN @@ -66,7 +64,6 @@ export = { hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', stack, node: stack.node, - construct: stack.construct, }); // THEN @@ -86,7 +83,6 @@ export = { hostedZoneArn: 'arn:aws:route53:::hostedzone/fakeId', stack, node: stack.node, - construct: stack.construct, }); // THEN diff --git a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts index 63f4b3750b990..e457de127d442 100644 --- a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts +++ b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts @@ -176,7 +176,7 @@ export class Asset extends cdk.Construct implements cdk.IAsset { * (e.g. "Code" for AWS::Lambda::Function) */ public addResourceMetadata(resource: cdk.CfnResource, resourceProperty: string) { - if (!this.construct.tryGetContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT)) { + if (!this.node.tryGetContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT)) { return; // not enabled } diff --git a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts index 7038155bde688..d08005a39f692 100644 --- a/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts +++ b/packages/@aws-cdk/aws-s3-assets/test/asset.test.ts @@ -24,7 +24,7 @@ test('simple use case', () => { // verify that metadata contains an "aws:cdk:asset" entry with // the correct information - const entry = stack.construct.metadata.find(m => m.type === 'aws:cdk:asset'); + const entry = stack.node.metadata.find(m => m.type === 'aws:cdk:asset'); expect(entry).toBeTruthy(); // verify that now the template contains parameters for this asset @@ -74,7 +74,7 @@ test('"file" assets', () => { const stack = new cdk.Stack(); const filePath = path.join(__dirname, 'file-asset.txt'); new Asset(stack, 'MyAsset', { path: filePath }); - const entry = stack.construct.metadata.find(m => m.type === 'aws:cdk:asset'); + const entry = stack.node.metadata.find(m => m.type === 'aws:cdk:asset'); expect(entry).toBeTruthy(); // synthesize first so "prepare" is called @@ -196,7 +196,7 @@ test('isZipArchive indicates if the asset represents a .zip file (either explici test('addResourceMetadata can be used to add CFN metadata to resources', () => { // GIVEN const stack = new cdk.Stack(); - stack.construct.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); + stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); const location = path.join(__dirname, 'sample-asset-directory'); const resource = new cdk.CfnResource(stack, 'MyResource', { type: 'My::Resource::Type' }); diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts index ec06a5a66c31c..6f0f877662891 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts @@ -77,7 +77,7 @@ export class Source { } let id = 1; - while (scope.construct.tryFindChild(`Asset${id}`)) { + while (scope.node.tryFindChild(`Asset${id}`)) { id++; } const asset = new s3_assets.Asset(scope, `Asset${id}`, { diff --git a/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts b/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts index 5cfb1cc918841..a1ea5ac5ac42c 100644 --- a/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts +++ b/packages/@aws-cdk/aws-s3-notifications/lib/lambda.ts @@ -11,7 +11,7 @@ export class LambdaDestination implements s3.IBucketNotificationDestination { } public bind(_scope: Construct, bucket: s3.IBucket): s3.BucketNotificationDestinationConfig { - const permissionId = `AllowBucketNotificationsFrom${bucket.construct.uniqueId}`; + const permissionId = `AllowBucketNotificationsFrom${bucket.node.uniqueId}`; if (this.fn.permissionsNode.tryFindChild(permissionId) === undefined) { this.fn.addPermission(permissionId, { diff --git a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts index fefd5b4b68b62..cadf2609692f0 100644 --- a/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts +++ b/packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts @@ -39,7 +39,7 @@ test('when notification are added, a custom resource is provisioned + a lambda h test('when notification are added, you can tag the lambda', () => { const stack = new cdk.Stack(); - stack.construct.applyAspect(new cdk.Tag('Lambda', 'AreTagged')); + stack.node.applyAspect(new cdk.Tag('Lambda', 'AreTagged')); const bucket = new s3.Bucket(stack, 'MyBucket'); diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 523b93bb84f71..acb1949b1cb2e 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -1425,7 +1425,7 @@ export class Bucket extends BucketBase { if (encryptionType === BucketEncryption.KMS) { const encryptionKey = props.encryptionKey || new kms.Key(this, 'Key', { - description: `Created by ${this.construct.path}`, + description: `Created by ${this.node.path}`, }); const bucketEncryption = { @@ -1623,7 +1623,7 @@ export class Bucket extends BucketBase { return this.inventories.map((inventory, index) => { const format = inventory.format ?? InventoryFormat.CSV; const frequency = inventory.frequency ?? InventoryFrequency.WEEKLY; - const id = inventory.inventoryId ?? `${this.construct.id}Inventory${index}`; + const id = inventory.inventoryId ?? `${this.node.id}Inventory${index}`; if (inventory.destination.bucket instanceof Bucket) { inventory.destination.bucket.addToResourcePolicy(new iam.PolicyStatement({ diff --git a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts index 1403ddcb2e7b4..4ceced2e93e2d 100644 --- a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts +++ b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource-handler.ts @@ -30,7 +30,7 @@ export class NotificationsResourceHandler extends cdk.Construct { // well-known logical id to ensure stack singletonity const logicalId = 'BucketNotificationsHandler050a0587b7544547bf325f094a3db834'; - let lambda = root.construct.tryFindChild(logicalId) as NotificationsResourceHandler; + let lambda = root.node.tryFindChild(logicalId) as NotificationsResourceHandler; if (!lambda) { lambda = new NotificationsResourceHandler(root, logicalId); } @@ -83,7 +83,7 @@ export class NotificationsResourceHandler extends cdk.Construct { }, }); - resource.construct.addDependency(role); + resource.node.addDependency(role); this.functionArn = resource.getAtt('Arn').toString(); } diff --git a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts index 99de445c4977c..fc5d83f8106d7 100644 --- a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts +++ b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts @@ -63,7 +63,7 @@ export class BucketNotifications extends cdk.Construct { // for example, the SNS topic policy must be created /before/ the notification resource. // otherwise, S3 won't be able to confirm the subscription. if (targetProps.dependencies) { - resource.construct.addDependency(...targetProps.dependencies); + resource.node.addDependency(...targetProps.dependencies); } // based on the target type, add the the correct configurations array diff --git a/packages/@aws-cdk/aws-s3/test/test.aspect.ts b/packages/@aws-cdk/aws-s3/test/test.aspect.ts index 8a74ff3b1cc7c..ba2049b0f993e 100644 --- a/packages/@aws-cdk/aws-s3/test/test.aspect.ts +++ b/packages/@aws-cdk/aws-s3/test/test.aspect.ts @@ -11,7 +11,7 @@ export = { new s3.Bucket(stack, 'MyBucket'); // WHEN - stack.construct.applyAspect(new BucketVersioningChecker()); + stack.node.applyAspect(new BucketVersioningChecker()); // THEN const assembly = SynthUtils.synthesize(stack); @@ -29,7 +29,7 @@ export = { }); // WHEN - stack.construct.applyAspect(new BucketVersioningChecker()); + stack.node.applyAspect(new BucketVersioningChecker()); // THEN const assembly = SynthUtils.synthesize(stack); @@ -44,7 +44,7 @@ class BucketVersioningChecker implements cdk.IAspect { if (node instanceof s3.CfnBucket) { if (!node.versioningConfiguration || (!cdk.Tokenization.isResolvable(node.versioningConfiguration) && node.versioningConfiguration.status !== 'Enabled')) { - node.construct.addError('Bucket versioning is not enabled'); + node.node.addError('Bucket versioning is not enabled'); } } } diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts index 7c87816854a86..16ff1056534bc 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret-rotation.ts @@ -211,7 +211,7 @@ export class SecretRotation extends Construct { } // Max length of 64 chars, get the last 64 chars - const uniqueId = this.construct.uniqueId; + const uniqueId = this.node.uniqueId; const rotationFunctionName = uniqueId.substring(Math.max(uniqueId.length - 64, 0), uniqueId.length); const securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'SecurityGroup', { diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index 4ca105f58d59a..1a256fb66aefd 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -315,7 +315,7 @@ export class Secret extends SecretBase { */ public attach(target: ISecretAttachmentTarget): ISecret { const id = 'Attachment'; - const existing = this.construct.tryFindChild(id); + const existing = this.node.tryFindChild(id); if (existing) { throw new Error('Secret is already attached to a target.'); diff --git a/packages/@aws-cdk/aws-servicediscovery/lib/alias-target-instance.ts b/packages/@aws-cdk/aws-servicediscovery/lib/alias-target-instance.ts index defbf3a1cd87c..2e9eb90f105d6 100644 --- a/packages/@aws-cdk/aws-servicediscovery/lib/alias-target-instance.ts +++ b/packages/@aws-cdk/aws-servicediscovery/lib/alias-target-instance.ts @@ -65,7 +65,7 @@ export class AliasTargetInstance extends InstanceBase { AWS_ALIAS_DNS_NAME: props.dnsName, ...props.customAttributes, }, - instanceId: props.instanceId || this.construct.uniqueId, + instanceId: props.instanceId || this.node.uniqueId, serviceId: props.service.serviceId, }); diff --git a/packages/@aws-cdk/aws-servicediscovery/lib/instance.ts b/packages/@aws-cdk/aws-servicediscovery/lib/instance.ts index c7567de4c8bc8..00e7d6a126934 100644 --- a/packages/@aws-cdk/aws-servicediscovery/lib/instance.ts +++ b/packages/@aws-cdk/aws-servicediscovery/lib/instance.ts @@ -50,7 +50,7 @@ export abstract class InstanceBase extends Resource implements IInstance { */ protected uniqueInstanceId() { // Max length of 64 chars, get the last 64 chars - const id = this.construct.uniqueId; + const id = this.node.uniqueId; return id.substring(Math.max(id.length - 64, 0), id.length); } } diff --git a/packages/@aws-cdk/aws-ses-actions/lib/lambda.ts b/packages/@aws-cdk/aws-ses-actions/lib/lambda.ts index b819672bc4755..3fa7d418e2ac4 100644 --- a/packages/@aws-cdk/aws-ses-actions/lib/lambda.ts +++ b/packages/@aws-cdk/aws-ses-actions/lib/lambda.ts @@ -68,10 +68,10 @@ export class Lambda implements ses.IReceiptRuleAction { // Ensure permission is deployed before rule const permission = this.props.function.permissionsNode.tryFindChild(permissionId) as lambda.CfnPermission; if (permission) { // The Lambda could be imported - rule.construct.addDependency(permission); + rule.node.addDependency(permission); } else { // eslint-disable-next-line max-len - rule.construct.addWarning('This rule is using a Lambda action with an imported function. Ensure permission is given to SES to invoke that function.'); + rule.node.addWarning('This rule is using a Lambda action with an imported function. Ensure permission is given to SES to invoke that function.'); } return { diff --git a/packages/@aws-cdk/aws-ses-actions/lib/s3.ts b/packages/@aws-cdk/aws-ses-actions/lib/s3.ts index 2e4129690fd80..24c8590511701 100644 --- a/packages/@aws-cdk/aws-ses-actions/lib/s3.ts +++ b/packages/@aws-cdk/aws-ses-actions/lib/s3.ts @@ -61,11 +61,11 @@ export class S3 implements ses.IReceiptRuleAction { }); this.props.bucket.addToResourcePolicy(s3Statement); - const policy = this.props.bucket.construct.tryFindChild('Policy') as s3.BucketPolicy; + const policy = this.props.bucket.node.tryFindChild('Policy') as s3.BucketPolicy; if (policy) { // The bucket could be imported - rule.construct.addDependency(policy); + rule.node.addDependency(policy); } else { - rule.construct.addWarning('This rule is using a S3 action with an imported bucket. Ensure permission is given to SES to write to that bucket.'); + rule.node.addWarning('This rule is using a S3 action with an imported bucket. Ensure permission is given to SES to write to that bucket.'); } // Allow SES to use KMS master key diff --git a/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts b/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts index 50bb1883777ec..943813184ed1f 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/lib/lambda.ts @@ -27,14 +27,14 @@ export class LambdaSubscription implements sns.ITopicSubscription { throw new Error('The supplied lambda Function object must be an instance of Construct'); } - this.fn.addPermission(`AllowInvoke:${topic.construct.uniqueId}`, { + this.fn.addPermission(`AllowInvoke:${topic.node.uniqueId}`, { sourceArn: topic.topicArn, principal: new iam.ServicePrincipal('sns.amazonaws.com'), }); return { subscriberScope: this.fn, - subscriberId: topic.construct.id, + subscriberId: topic.node.id, endpoint: this.fn.functionArn, protocol: sns.SubscriptionProtocol.LAMBDA, filterPolicy: this.props.filterPolicy, diff --git a/packages/@aws-cdk/aws-sns-subscriptions/lib/sqs.ts b/packages/@aws-cdk/aws-sns-subscriptions/lib/sqs.ts index 7ff0c6921571b..39c8362d60c4f 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/lib/sqs.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/lib/sqs.ts @@ -48,7 +48,7 @@ export class SqsSubscription implements sns.ITopicSubscription { return { subscriberScope: this.queue, - subscriberId: topic.construct.uniqueId, + subscriberId: topic.node.uniqueId, endpoint: this.queue.queueArn, protocol: sns.SubscriptionProtocol.SQS, rawMessageDelivery: this.props.rawMessageDelivery, diff --git a/packages/@aws-cdk/aws-sns/lib/topic-base.ts b/packages/@aws-cdk/aws-sns/lib/topic-base.ts index 84fee88c6821a..07b96a34629d2 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic-base.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic-base.ts @@ -73,8 +73,8 @@ export abstract class TopicBase extends Resource implements ITopic { // We use the subscriber's id as the construct id. There's no meaning // to subscribing the same subscriber twice on the same topic. - if (scope.construct.tryFindChild(id)) { - throw new Error(`A subscription with id "${id}" already exists under the scope ${scope.construct.path}`); + if (scope.node.tryFindChild(id)) { + throw new Error(`A subscription with id "${id}" already exists under the scope ${scope.node.path}`); } new Subscription(scope, id, { @@ -125,8 +125,8 @@ export abstract class TopicBase extends Resource implements ITopic { const re = /TokenSubscription:([\d]*)/gm; // Search through the construct and all of its children // for previous subscriptions that match our regex pattern - for (const source of scope.construct.findAll()) { - const m = re.exec(source.construct.id); // Use regex to find a match + for (const source of scope.node.findAll()) { + const m = re.exec(source.node.id); // Use regex to find a match if (m !== null) { // if we found a match const matchSuffix = parseInt(m[1], 10); // get the suffix for that match (as integer) if (matchSuffix >= nextSuffix) { // check if the match suffix is larger or equal to currently proposed suffix diff --git a/packages/@aws-cdk/aws-sqs/lib/queue.ts b/packages/@aws-cdk/aws-sqs/lib/queue.ts index b8840e9c9af89..d335da2c9120f 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue.ts @@ -302,7 +302,7 @@ export class Queue extends QueueBase { if (encryption === QueueEncryption.KMS) { const masterKey = props.encryptionMasterKey || new kms.Key(this, 'Key', { - description: `Created by ${this.construct.path}`, + description: `Created by ${this.node.path}`, }); return { diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index 27491975dd81f..bc73278bfc267 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -390,7 +390,7 @@ export class StringParameter extends ParameterBase implements IStringParameter { public static valueForTypedStringParameter(scope: Construct, parameterName: string, type = ParameterType.STRING, version?: number): string { const stack = Stack.of(scope); const id = makeIdentityForImportedValue(parameterName); - const exists = stack.construct.tryFindChild(id) as IStringParameter; + const exists = stack.node.tryFindChild(id) as IStringParameter; if (exists) { return exists.stringValue; } @@ -406,7 +406,7 @@ export class StringParameter extends ParameterBase implements IStringParameter { public static valueForSecureStringParameter(scope: Construct, parameterName: string, version: number): string { const stack = Stack.of(scope); const id = makeIdentityForImportedValue(parameterName); - const exists = stack.construct.tryFindChild(id) as IStringParameter; + const exists = stack.node.tryFindChild(id) as IStringParameter; if (exists) { return exists.stringValue; } return this.fromSecureStringParameterAttributes(stack, id, { parameterName, version }).stringValue; diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter-arns.ts b/packages/@aws-cdk/aws-ssm/test/integ.parameter-arns.ts index 2fb19bd2a9367..358d92abbce25 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter-arns.ts +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter-arns.ts @@ -19,7 +19,7 @@ const params = [ ]; for (const p of params) { - new CfnOutput(stack, `${p.construct.id}Arn`, { value: p.parameterArn }); + new CfnOutput(stack, `${p.node.id}Arn`, { value: p.parameterArn }); } app.synth(); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-ecs-task-base.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-ecs-task-base.ts index b38efbf39865f..12d1c71665577 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-ecs-task-base.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-ecs-task-base.ts @@ -89,7 +89,7 @@ export class EcsRunTaskBase implements ec2.IConnectable, sfn.IStepFunctionsTask for (const override of this.props.containerOverrides || []) { const name = override.containerDefinition.containerName; if (!cdk.Token.isUnresolved(name)) { - const cont = this.props.taskDefinition.construct.tryFindChild(name); + const cont = this.props.taskDefinition.node.tryFindChild(name); if (!cont) { throw new Error(`Overrides mention container with name '${name}', but no such container in task definition`); } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-task.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-task.ts index 371fc65a461c6..d06d204641653 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-task.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/ecs/run-task.ts @@ -260,7 +260,7 @@ export class EcsRunTask extends sfn.TaskStateBase implements ec2.IConnectable { for (const override of this.props.containerOverrides ?? []) { const name = override.containerDefinition.containerName; if (!cdk.Token.isUnresolved(name)) { - const cont = this.props.taskDefinition.construct.tryFindChild(name); + const cont = this.props.taskDefinition.node.tryFindChild(name); if (!cont) { throw new Error(`Overrides mention container with name '${name}', but no such container in task definition`); } diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/activity.ts b/packages/@aws-cdk/aws-stepfunctions/lib/activity.ts index 5a011fbf0bd74..ef97f45e6f8b3 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/activity.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/activity.ts @@ -185,7 +185,7 @@ export class Activity extends Resource implements IActivity { } private generateName(): string { - const name = this.construct.uniqueId; + const name = this.node.uniqueId; if (name.length > 80) { return name.substring(0, 40) + name.substring(name.length - 40); } diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine-fragment.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine-fragment.ts index 5a9e8884d22b0..929aed5b22219 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine-fragment.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine-fragment.ts @@ -19,7 +19,7 @@ export abstract class StateMachineFragment extends cdk.Construct implements ICha public abstract readonly endStates: INextable[]; public get id() { - return this.construct.id; + return this.node.id; } /** diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts index 663f3346892fa..a6632a7e5d35d 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts @@ -305,7 +305,7 @@ export class StateMachine extends StateMachineBase { loggingConfiguration, }); - resource.construct.addDependency(this.role); + resource.node.addDependency(this.role); for (const statement of graph.policyStatements) { this.addToRolePolicy(statement); diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts b/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts index 8c4701764c7cf..d586a3e472d98 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts @@ -70,7 +70,7 @@ export abstract class State extends cdk.Construct implements IChainable { if (isPrefixable(el)) { el.addPrefix(prefix); } - queue.push(...el.construct.children); + queue.push(...el.node.children); } } @@ -186,7 +186,7 @@ export abstract class State extends cdk.Construct implements IChainable { } public get id() { - return this.construct.id; + return this.node.id; } /** diff --git a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts index 40625bd8b7b0a..845aa001ba3d2 100644 --- a/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/valid-templates.test.ts @@ -297,7 +297,7 @@ describe('CDK Include', () => { const cfnTemplate = includeTestTemplate(stack, 'resource-attribute-depends-on.json'); const cfnBucket2 = cfnTemplate.getResource('Bucket2'); - expect(cfnBucket2.construct.dependencies).toHaveLength(1); + expect(cfnBucket2.node.dependencies).toHaveLength(1); // we always render dependsOn as an array, even if it's a single string expect(stack).toHaveResourceLike('AWS::S3::Bucket', { "Properties": { @@ -313,7 +313,7 @@ describe('CDK Include', () => { const cfnTemplate = includeTestTemplate(stack, 'resource-attribute-depends-on-array.json'); const cfnBucket2 = cfnTemplate.getResource('Bucket2'); - expect(cfnBucket2.construct.dependencies).toHaveLength(2); + expect(cfnBucket2.node.dependencies).toHaveLength(2); expect(stack).toHaveResourceLike('AWS::S3::Bucket', { "Properties": { "BucketName": "bucket2", diff --git a/packages/@aws-cdk/core/README.md b/packages/@aws-cdk/core/README.md index d6a5d9a902032..d2a240166995c 100644 --- a/packages/@aws-cdk/core/README.md +++ b/packages/@aws-cdk/core/README.md @@ -214,7 +214,7 @@ you. If you need to add an ordering dependency that is not automatically inferred, you do so by adding a dependency relationship using -`constructA.construct.addDependency(constructB)`. This will add a dependency +`constructA.node.addDependency(constructB)`. This will add a dependency relationship between all resources in the scope of `constructA` and all resources in the scope of `constructB`. @@ -230,7 +230,7 @@ bAndC.add(constructB); bAndC.add(constructC); // Take the dependency -constructA.construct.addDependency(bAndC); +constructA.node.addDependency(bAndC); ``` ### Stack Dependencies @@ -319,7 +319,7 @@ examples ensures that only a single SNS topic is defined: function getOrCreate(scope: Construct): sns.Topic { const stack = Stack.of(this); const uniqueid = 'GloballyUniqueIdForSingleton'; - return stack.construct.tryFindChild(uniqueid) as sns.Topic ?? new sns.Topic(stack, uniqueid); + return stack.node.tryFindChild(uniqueid) as sns.Topic ?? new sns.Topic(stack, uniqueid); } ``` @@ -675,7 +675,7 @@ accessing those through the `cfnOptions` property: ```ts const rawBucket = new s3.CfnBucket(this, 'Bucket', { /* ... */ }); // -or- -const rawBucket = bucket.construct.defaultChild as s3.CfnBucket; +const rawBucket = bucket.node.defaultChild as s3.CfnBucket; // then rawBucket.cfnOptions.condition = new CfnCondition(this, 'EnableBucket', { /* ... */ }); @@ -734,7 +734,7 @@ const stage = Fn.conditionIf(isProd.logicalId, 'Beta', 'Prod').toString(); // Make Bucket creation condition to IsProduction by accessing // and overriding the CloudFormation resource const bucket = new s3.Bucket(this, 'Bucket'); -const cfnBucket = bucket.construct.defaultChild as s3.CfnBucket; +const cfnBucket = bucket.node.defaultChild as s3.CfnBucket; cfnBucket.cfnOptions.condition = isProd; ``` diff --git a/packages/@aws-cdk/core/lib/annotations.ts b/packages/@aws-cdk/core/lib/annotations.ts index a90ab995441a1..8f13e09987035 100644 --- a/packages/@aws-cdk/core/lib/annotations.ts +++ b/packages/@aws-cdk/core/lib/annotations.ts @@ -55,6 +55,6 @@ export class Annotations { * @param message The message itself */ private addMessage(level: string, message: string) { - this.scope.construct.addMetadata(level, message); + this.scope.node.addMetadata(level, message); } } \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/app.ts b/packages/@aws-cdk/core/lib/app.ts index ba87fe7a86197..50996a72ff85a 100644 --- a/packages/@aws-cdk/core/lib/app.ts +++ b/packages/@aws-cdk/core/lib/app.ts @@ -98,11 +98,11 @@ export class App extends Stage { this.loadContext(props.context); if (props.stackTraces === false) { - this.construct.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true); + this.node.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true); } if (props.runtimeInfo === false) { - this.construct.setContext(cxapi.DISABLE_VERSION_REPORTING, true); + this.node.setContext(cxapi.DISABLE_VERSION_REPORTING, true); } const autoSynth = props.autoSynth !== undefined ? props.autoSynth : cxapi.OUTDIR_ENV in process.env; @@ -120,7 +120,7 @@ export class App extends Stage { private loadContext(defaults: { [key: string]: string } = { }) { // prime with defaults passed through constructor for (const [ k, v ] of Object.entries(defaults)) { - this.construct.setContext(k, v); + this.node.setContext(k, v); } // read from environment @@ -130,7 +130,7 @@ export class App extends Stage { : { }; for (const [ k, v ] of Object.entries(contextFromEnvironment)) { - this.construct.setContext(k, v); + this.node.setContext(k, v); } } } diff --git a/packages/@aws-cdk/core/lib/aspect.ts b/packages/@aws-cdk/core/lib/aspect.ts index 8bf84d4d3f22f..3bca67a12aa6d 100644 --- a/packages/@aws-cdk/core/lib/aspect.ts +++ b/packages/@aws-cdk/core/lib/aspect.ts @@ -45,7 +45,7 @@ export class Aspects { */ public add(aspect: IAspect) { // TODO(2.0): this._aspects.push(aspect); - this.scope.construct._actualNode.applyAspect(aspect); + this.scope.node._actualNode.applyAspect(aspect); } /** @@ -53,6 +53,6 @@ export class Aspects { */ public get aspects(): IAspect[] { // TODO(2.0): return [ ...this._aspects ]; - return [ ...(this.scope.construct._actualNode as any)._aspects ]; // clone + return [ ...(this.scope.node._actualNode as any)._aspects ]; // clone } } \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/asset-staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts index 8a3ae1452b464..d581f3df6bc84 100644 --- a/packages/@aws-cdk/core/lib/asset-staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -5,9 +5,9 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as fs from 'fs-extra'; import { AssetHashType, AssetOptions } from './assets'; import { BundlingOptions } from './bundling'; -import { Construct } from './construct-compat'; import { FileSystem, FingerprintOptions } from './fs'; import { Stage } from './stage'; +import { Construct } from './construct-compat'; const STAGING_TMP = '.cdk.staging'; @@ -95,7 +95,7 @@ export class AssetStaging extends Construct { this.assetHash = this.calculateHash(props); - const stagingDisabled = this.construct.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT); + const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT); if (stagingDisabled) { this.stagedPath = this.bundleDir ?? this.sourcePath; } else { @@ -180,7 +180,7 @@ export class AssetStaging extends Construct { let localBundling: boolean | undefined; try { - process.stderr.write(`Bundling asset ${this.construct.path}...\n`); + process.stderr.write(`Bundling asset ${this.node.path}...\n`); localBundling = options.local?.tryBundle(bundleDir, options); if (!localBundling) { @@ -193,7 +193,7 @@ export class AssetStaging extends Construct { }); } } catch (err) { - throw new Error(`Failed to bundle asset ${this.construct.path}: ${err}`); + throw new Error(`Failed to bundle asset ${this.node.path}: ${err}`); } if (FileSystem.isEmpty(bundleDir)) { diff --git a/packages/@aws-cdk/core/lib/cfn-element.ts b/packages/@aws-cdk/core/lib/cfn-element.ts index 2e6562b247f79..7aadf278f13cd 100644 --- a/packages/@aws-cdk/core/lib/cfn-element.ts +++ b/packages/@aws-cdk/core/lib/cfn-element.ts @@ -58,10 +58,10 @@ export abstract class CfnElement extends Construct { this.stack = Stack.of(this); this.logicalId = Lazy.stringValue({ produce: () => this.synthesizeLogicalId() }, { - displayHint: `${notTooLong(this.construct.path)}.LogicalID`, + displayHint: `${notTooLong(this.node.path)}.LogicalID`, }); - this.construct.addMetadata(cxschema.ArtifactMetadataEntryType.LOGICAL_ID, this.logicalId, this.constructor); + this.node.addMetadata(cxschema.ArtifactMetadataEntryType.LOGICAL_ID, this.logicalId, this.constructor); } /** @@ -78,7 +78,7 @@ export abstract class CfnElement extends Construct { * node +internal+ entries filtered. */ public get creationStack(): string[] { - const trace = this.construct.metadata.find(md => md.type === cxschema.ArtifactMetadataEntryType.LOGICAL_ID)!.trace; + const trace = this.node.metadata.find(md => md.type === cxschema.ArtifactMetadataEntryType.LOGICAL_ID)!.trace; if (!trace) { return []; } diff --git a/packages/@aws-cdk/core/lib/cfn-output.ts b/packages/@aws-cdk/core/lib/cfn-output.ts index 4714f3d99cf3d..3f2784f890073 100644 --- a/packages/@aws-cdk/core/lib/cfn-output.ts +++ b/packages/@aws-cdk/core/lib/cfn-output.ts @@ -50,7 +50,7 @@ export class CfnOutput extends CfnElement { super(scope, id); if (props.value === undefined) { - throw new Error(`Missing value for CloudFormation output at path "${this.construct.path}"`); + throw new Error(`Missing value for CloudFormation output at path "${this.node.path}"`); } this._description = props.description; diff --git a/packages/@aws-cdk/core/lib/cfn-parse.ts b/packages/@aws-cdk/core/lib/cfn-parse.ts index a58e54f097be4..5872399e0efee 100644 --- a/packages/@aws-cdk/core/lib/cfn-parse.ts +++ b/packages/@aws-cdk/core/lib/cfn-parse.ts @@ -221,7 +221,7 @@ export class CfnParser { if (!depResource) { throw new Error(`Resource '${logicalId}' depends on '${dep}' that doesn't exist`); } - resource.construct.addDependency(depResource); + resource.node.addDependency(depResource); } } diff --git a/packages/@aws-cdk/core/lib/cfn-resource.ts b/packages/@aws-cdk/core/lib/cfn-resource.ts index 45ad083e5591d..9af3aa5c16a21 100644 --- a/packages/@aws-cdk/core/lib/cfn-resource.ts +++ b/packages/@aws-cdk/core/lib/cfn-resource.ts @@ -92,8 +92,8 @@ export class CfnResource extends CfnRefElement { // if aws:cdk:enable-path-metadata is set, embed the current construct's // path in the CloudFormation template, so it will be possible to trace // back to the actual construct path. - if (this.construct.tryGetContext(cxapi.PATH_METADATA_ENABLE_CONTEXT)) { - this.addMetadata(cxapi.PATH_METADATA_KEY, this.construct.path); + if (this.node.tryGetContext(cxapi.PATH_METADATA_ENABLE_CONTEXT)) { + this.addMetadata(cxapi.PATH_METADATA_KEY, this.node.path); } } @@ -238,7 +238,7 @@ export class CfnResource extends CfnRefElement { return; } - addDependency(this, target, `"${this.construct.path}" depends on "${target.construct.path}"`); + addDependency(this, target, `"${this.node.path}" depends on "${target.node.path}"`); } /** @@ -312,7 +312,7 @@ export class CfnResource extends CfnRefElement { return ret; } catch (e) { // Change message - e.message = `While synthesizing ${this.construct.path}: ${e.message}`; + e.message = `While synthesizing ${this.node.path}: ${e.message}`; // Adjust stack trace (make it look like node built it, too...) const trace = this.creationStack; if (trace) { @@ -330,7 +330,7 @@ export class CfnResource extends CfnRefElement { function renderDependsOn(dependsOn: Set) { return Array .from(dependsOn) - .sort((x, y) => x.construct.path.localeCompare(y.construct.path)) + .sort((x, y) => x.node.path.localeCompare(y.node.path)) .map(r => r.logicalId); } diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index 572fa9f33fe8f..306e299016f7c 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -28,11 +28,6 @@ export interface IConstruct extends constructs.IConstruct, IDependable { * The construct tree node for this construct. */ readonly node: ConstructNode; - - /** - * The construct tree node for this construct. - */ - readonly construct: ConstructNode; } /** @@ -66,18 +61,9 @@ export class Construct extends constructs.Construct implements IConstruct { /** * The construct tree node associated with this construct. - * - * @deprecate `Construct.node` is being deprecated in favor of - * `Construct.construct`. This API will be removed in the next major version - * of the AWS CDK, please migrate your code to use `construct` instead. */ public readonly node: ConstructNode; - /** - * Construct API. - */ - public readonly construct: ConstructNode; - constructor(scope: Construct, id: string) { super(scope, id, { nodeFactory: { @@ -91,17 +77,16 @@ export class Construct extends constructs.Construct implements IConstruct { } Object.defineProperty(this, CONSTRUCT_SYMBOL, { value: true }); - this.construct = ConstructNode._unwrap(constructs.Node.of(this)); - this.node = this.construct; + this.node = ConstructNode._unwrap(constructs.Node.of(this)); const disableTrace = - this.construct.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) || - this.construct.tryGetContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA) || + this.node.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) || + this.node.tryGetContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA) || process.env.CDK_DISABLE_STACK_TRACE; if (disableTrace) { - this.construct.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true); - this.construct.setContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA, true); + this.node.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true); + this.node.setContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA, true); process.env.CDK_DISABLE_STACK_TRACE = '1'; } } diff --git a/packages/@aws-cdk/core/lib/context-provider.ts b/packages/@aws-cdk/core/lib/context-provider.ts index 9d176709cb778..6a01a7c5a6506 100644 --- a/packages/@aws-cdk/core/lib/context-provider.ts +++ b/packages/@aws-cdk/core/lib/context-provider.ts @@ -95,7 +95,7 @@ export class ContextProvider { } const { key, props } = this.getKey(scope, options); - const value = scope.construct.tryGetContext(key); + const value = scope.node.tryGetContext(key); const providerError = extractProviderError(value); // if context is missing or an error occurred during context retrieval, diff --git a/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts b/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts index 21decaf371076..8b24d068235f9 100644 --- a/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts +++ b/packages/@aws-cdk/core/lib/custom-resource-provider/custom-resource-provider.ts @@ -91,7 +91,7 @@ export class CustomResourceProvider extends Construct { public static getOrCreate(scope: Construct, uniqueid: string, props: CustomResourceProviderProps) { const id = `${uniqueid}CustomResourceProvider`; const stack = Stack.of(scope); - const provider = stack.construct.tryFindChild(id) as CustomResourceProvider + const provider = stack.node.tryFindChild(id) as CustomResourceProvider ?? new CustomResourceProvider(stack, id, props); return provider.serviceToken; diff --git a/packages/@aws-cdk/core/lib/deps.ts b/packages/@aws-cdk/core/lib/deps.ts index 55726d7dac46e..e0ef970b6e359 100644 --- a/packages/@aws-cdk/core/lib/deps.ts +++ b/packages/@aws-cdk/core/lib/deps.ts @@ -36,7 +36,7 @@ export function addDependency(source: T, target: T, reason?: const targetStage = Stage.of(targetStack); if (sourceStage !== targetStage) { // eslint-disable-next-line max-len - throw new Error(`You cannot add a dependency from '${source.construct.path}' (in ${describeStage(sourceStage)}) to '${target.construct.path}' (in ${describeStage(targetStage)}): dependency cannot cross stage boundaries`); + throw new Error(`You cannot add a dependency from '${source.node.path}' (in ${describeStage(sourceStage)}) to '${target.node.path}' (in ${describeStage(targetStage)}): dependency cannot cross stage boundaries`); } // find the deepest common stack between the two elements @@ -70,7 +70,7 @@ export function addDependency(source: T, target: T, reason?: // `source` is a direct or indirect nested stack of `target`, and this is not // possible (nested stacks cannot depend on their parents). if (commonStack === target) { - throw new Error(`Nested stack '${sourceStack.construct.path}' cannot depend on a parent stack '${targetStack.construct.path}': ${reason}`); + throw new Error(`Nested stack '${sourceStack.node.path}' cannot depend on a parent stack '${targetStack.node.path}': ${reason}`); } // we have a common stack from which we can reach both `source` and `target` @@ -103,5 +103,5 @@ export function addDependency(source: T, target: T, reason?: function describeStage(assembly: Stage | undefined): string { if (!assembly) { return 'an unrooted construct tree'; } if (!assembly.parentStage) { return 'the App'; } - return `Stage '${assembly.construct.path}'`; + return `Stage '${assembly.node.path}'`; } diff --git a/packages/@aws-cdk/core/lib/nested-stack.ts b/packages/@aws-cdk/core/lib/nested-stack.ts index cd9e6be048d44..7e52427467039 100644 --- a/packages/@aws-cdk/core/lib/nested-stack.ts +++ b/packages/@aws-cdk/core/lib/nested-stack.ts @@ -110,7 +110,7 @@ export class NestedStack extends Stack { Object.defineProperty(this, NESTED_STACK_SYMBOL, { value: true }); // this is the file name of the synthesized template file within the cloud assembly - this.templateFile = `${this.construct.uniqueId}.nested.template.json`; + this.templateFile = `${this.node.uniqueId}.nested.template.json`; this.parameters = props.parameters || {}; @@ -223,7 +223,7 @@ function findParentStack(scope: Construct): Stack { throw new Error('Nested stacks cannot be defined as a root construct'); } - const parentStack = scope.construct.scopes.reverse().find(p => Stack.isStack(p)); + const parentStack = scope.node.scopes.reverse().find(p => Stack.isStack(p)); if (!parentStack) { throw new Error('Nested stacks must be defined within scope of another non-nested stack'); } diff --git a/packages/@aws-cdk/core/lib/private/cfn-reference.ts b/packages/@aws-cdk/core/lib/private/cfn-reference.ts index a20457d7f6e6d..491232e344840 100644 --- a/packages/@aws-cdk/core/lib/private/cfn-reference.ts +++ b/packages/@aws-cdk/core/lib/private/cfn-reference.ts @@ -102,6 +102,11 @@ export class CfnReference extends Reference { const consumingStack = Stack.of(context.scope); const token = this.replacementTokens.get(consumingStack); + // if (!token && this.isCrossStackReference(consumingStack) && !context.preparing) { + // eslint-disable-next-line max-len + // throw new Error(`Cross-stack reference (${context.scope.node.path} -> ${this.target.node.path}) has not been assigned a value--call prepare() first`); + // } + if (token) { return token.resolve(context); } else { @@ -133,7 +138,7 @@ export class CfnReference extends Reference { */ public toString(): string { return Token.asString(this, { - displayHint: `${this.target.construct.id}.${this.displayName}`, + displayHint: `${this.target.node.id}.${this.displayName}`, }); } } diff --git a/packages/@aws-cdk/core/lib/private/physical-name-generator.ts b/packages/@aws-cdk/core/lib/private/physical-name-generator.ts index 993c63c1db211..dbd0a2c8af772 100644 --- a/packages/@aws-cdk/core/lib/private/physical-name-generator.ts +++ b/packages/@aws-cdk/core/lib/private/physical-name-generator.ts @@ -8,16 +8,16 @@ import { TokenMap } from './token-map'; export function generatePhysicalName(resource: IResource): string { const stack = Stack.of(resource); const stackPart = new PrefixNamePart(stack.stackName, 25); - const idPart = new SuffixNamePart(resource.construct.uniqueId, 24); + const idPart = new SuffixNamePart(resource.node.uniqueId, 24); const region: string = stack.region; if (Token.isUnresolved(region) || !region) { - throw new Error(`Cannot generate a physical name for ${resource.construct.path}, because the region is un-resolved or missing`); + throw new Error(`Cannot generate a physical name for ${resource.node.path}, because the region is un-resolved or missing`); } const account: string = stack.account; if (Token.isUnresolved(account) || !account) { - throw new Error(`Cannot generate a physical name for ${resource.construct.path}, because the account is un-resolved or missing`); + throw new Error(`Cannot generate a physical name for ${resource.node.path}, because the account is un-resolved or missing`); } const parts = [stackPart, idPart] diff --git a/packages/@aws-cdk/core/lib/private/prepare-app.ts b/packages/@aws-cdk/core/lib/private/prepare-app.ts index a8d1d33ed04d1..ad900acf803c0 100644 --- a/packages/@aws-cdk/core/lib/private/prepare-app.ts +++ b/packages/@aws-cdk/core/lib/private/prepare-app.ts @@ -17,7 +17,7 @@ import { resolveReferences } from './refs'; */ export function prepareApp(root: IConstruct) { // apply dependencies between resources in depending subtrees - for (const dependency of root.construct.dependencies) { + for (const dependency of root.node.dependencies) { const targetCfnResources = findCfnResources(dependency.target); const sourceCfnResources = findCfnResources(dependency.source); @@ -71,7 +71,7 @@ function findAllNestedStacks(root: IConstruct) { // create a list of all nested stacks in depth-first post order this means // that we first prepare the leaves and then work our way up. - for (const stack of root.construct.findAll(ConstructOrder.POSTORDER /* <== important */)) { + for (const stack of root.node.findAll(ConstructOrder.POSTORDER /* <== important */)) { if (includeStack(stack)) { result.push(stack); } @@ -84,7 +84,7 @@ function findAllNestedStacks(root: IConstruct) { * Find all resources in a set of constructs */ function findCfnResources(root: IConstruct): CfnResource[] { - return root.construct.findAll().filter(CfnResource.isCfnResource); + return root.node.findAll().filter(CfnResource.isCfnResource); } interface INestedStackPrivateApi { diff --git a/packages/@aws-cdk/core/lib/private/refs.ts b/packages/@aws-cdk/core/lib/private/refs.ts index 43c6c4e0a8422..c852f0b94b96b 100644 --- a/packages/@aws-cdk/core/lib/private/refs.ts +++ b/packages/@aws-cdk/core/lib/private/refs.ts @@ -46,14 +46,14 @@ function resolveValue(consumer: Stack, reference: CfnReference): IResolvable { } // unsupported: stacks from different apps - if (producer.construct.root !== consumer.construct.root) { + if (producer.node.root !== consumer.node.root) { throw new Error('Cannot reference across apps. Consuming and producing stacks must be defined within the same CDK app.'); } // unsupported: stacks are not in the same environment if (producer.environment !== consumer.environment) { throw new Error( - `Stack "${consumer.construct.path}" cannot consume a cross reference from stack "${producer.construct.path}". ` + + `Stack "${consumer.node.path}" cannot consume a cross reference from stack "${producer.node.path}". ` + 'Cross stack references are only supported for stacks deployed to the same environment or between nested stacks and their parent stack'); } @@ -99,7 +99,7 @@ function resolveValue(consumer: Stack, reference: CfnReference): IResolvable { // will take care of applying the dependency at the right level (e.g. the // top-level stacks). consumer.addDependency(producer, - `${consumer.construct.path} -> ${reference.target.construct.path}.${reference.displayName}`); + `${consumer.node.path} -> ${reference.target.node.path}.${reference.displayName}`); return createImportValue(reference); } @@ -109,7 +109,7 @@ function resolveValue(consumer: Stack, reference: CfnReference): IResolvable { */ function findAllReferences(root: IConstruct) { const result = new Array<{ source: CfnElement, value: CfnReference }>(); - for (const consumer of root.construct.findAll()) { + for (const consumer of root.node.findAll()) { // include only CfnElements (i.e. resources) if (!CfnElement.isCfnElement(consumer)) { @@ -180,7 +180,7 @@ function createImportValue(reference: Reference): Intrinsic { throw new Error(`unresolved token in generated export name: ${JSON.stringify(exportingStack.resolve(exportName))}`); } - const output = exportsScope.construct.tryFindChild(id) as CfnOutput; + const output = exportsScope.node.tryFindChild(id) as CfnOutput; if (!output) { new CfnOutput(exportsScope, id, { value: Token.asString(reference), exportName }); } @@ -192,7 +192,7 @@ function createImportValue(reference: Reference): Intrinsic { function getCreateExportsScope(stack: Stack) { const exportsName = 'Exports'; - let stackExports = stack.construct.tryFindChild(exportsName) as Construct; + let stackExports = stack.node.tryFindChild(exportsName) as Construct; if (stackExports === undefined) { stackExports = new Construct(stack, exportsName); } @@ -201,13 +201,13 @@ function getCreateExportsScope(stack: Stack) { } function generateExportName(stackExports: Construct, id: string) { - const stackRelativeExports = stackExports.construct.tryGetContext(cxapi.STACK_RELATIVE_EXPORTS_CONTEXT); + const stackRelativeExports = stackExports.node.tryGetContext(cxapi.STACK_RELATIVE_EXPORTS_CONTEXT); const stack = Stack.of(stackExports); const components = [ - ...stackExports.construct.scopes - .slice(stackRelativeExports ? stack.construct.scopes.length : 2) - .map(c => c.construct.id), + ...stackExports.node.scopes + .slice(stackRelativeExports ? stack.node.scopes.length : 2) + .map(c => c.node.id), id, ]; const prefix = stack.stackName ? stack.stackName + ':' : ''; @@ -225,8 +225,8 @@ function generateExportName(stackExports: Construct, id: string) { */ function createNestedStackParameter(nested: Stack, reference: CfnReference, value: IResolvable) { // we call "this.resolve" to ensure that tokens do not creep in (for example, if the reference display name includes tokens) - const paramId = nested.resolve(`reference-to-${reference.target.construct.uniqueId}.${reference.displayName}`); - let param = nested.construct.tryFindChild(paramId) as CfnParameter; + const paramId = nested.resolve(`reference-to-${reference.target.node.uniqueId}.${reference.displayName}`); + let param = nested.node.tryFindChild(paramId) as CfnParameter; if (!param) { param = new CfnParameter(nested, paramId, { type: 'String' }); @@ -246,8 +246,8 @@ function createNestedStackParameter(nested: Stack, reference: CfnReference, valu * intrinsic that can be used to reference this output in the parent stack. */ function createNestedStackOutput(producer: Stack, reference: Reference): CfnReference { - const outputId = `${reference.target.construct.uniqueId}${reference.displayName}`; - let output = producer.construct.tryFindChild(outputId) as CfnOutput; + const outputId = `${reference.target.node.uniqueId}${reference.displayName}`; + let output = producer.node.tryFindChild(outputId) as CfnOutput; if (!output) { output = new CfnOutput(producer, outputId, { value: Token.asString(reference) }); } diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index d335c6181dfa6..b4d2368ae6c99 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -46,7 +46,7 @@ export function synthesize(root: IConstruct, options: SynthesisOptions = { }): c * (They will in turn recurse again) */ function synthNestedAssemblies(root: IConstruct, options: StageSynthesisOptions) { - for (const child of root.construct.children) { + for (const child of root.node.children) { if (Stage.isStage(child)) { child.synth(options); } else { @@ -68,7 +68,7 @@ function invokeAspects(root: IConstruct) { recurse(root, []); function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) { - const node = construct.construct; + const node = construct.node; const aspects = Aspects.of(construct); const allAspectsHere = [...inheritedAspects ?? [], ...aspects.aspects]; const nodeAspectsCount = aspects.aspects.length; @@ -93,7 +93,7 @@ function invokeAspects(root: IConstruct) { invoked.push(aspect); } - for (const child of construct.construct.children) { + for (const child of construct.node.children) { if (!Stage.isStage(child)) { recurse(child, allAspectsHere); } @@ -147,7 +147,7 @@ function validateTree(root: IConstruct) { }); if (errors.length > 0) { - const errorList = errors.map(e => `[${e.source.construct.path}] ${e.message}`).join('\n '); + const errorList = errors.map(e => `[${e.source.node.path}] ${e.message}`).join('\n '); throw new Error(`Validation failed with the following errors:\n ${errorList}`); } } @@ -160,7 +160,7 @@ function visit(root: IConstruct, order: 'pre' | 'post', cb: (x: IProtectedConstr cb(root as IProtectedConstructMethods); } - for (const child of root.construct.children) { + for (const child of root.node.children) { if (Stage.isStage(child)) { continue; } visit(child, order, cb); } diff --git a/packages/@aws-cdk/core/lib/private/tree-metadata.ts b/packages/@aws-cdk/core/lib/private/tree-metadata.ts index 5e87c96b027e1..eb18252a0e8bd 100644 --- a/packages/@aws-cdk/core/lib/private/tree-metadata.ts +++ b/packages/@aws-cdk/core/lib/private/tree-metadata.ts @@ -29,11 +29,11 @@ export class TreeMetadata extends Construct { const lookup: { [path: string]: Node } = { }; const visit = (construct: IConstruct): Node => { - const children = construct.construct.children.map((c) => { + const children = construct.node.children.map((c) => { try { return visit(c); } catch (e) { - Annotations.of(this).addWarning(`Failed to render tree metadata for node [${c.construct.id}]. Reason: ${e}`); + Annotations.of(this).addWarning(`Failed to render tree metadata for node [${c.node.id}]. Reason: ${e}`); return undefined; } }); @@ -42,8 +42,8 @@ export class TreeMetadata extends Construct { .reduce((map, child) => Object.assign(map, { [child!.id]: child }), {}); const node: Node = { - id: construct.construct.id || 'App', - path: construct.construct.path, + id: construct.node.id || 'App', + path: construct.node.path, children: Object.keys(childrenMap).length === 0 ? undefined : childrenMap, attributes: this.synthAttributes(construct), }; @@ -55,7 +55,7 @@ export class TreeMetadata extends Construct { const tree = { version: 'tree-0.1', - tree: visit(this.construct.root), + tree: visit(this.node.root), }; const builder = session.assembly; diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index 129deed73d04f..6574dbe331da0 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -96,7 +96,7 @@ export abstract class Resource extends Construct implements IResource { public _enableCrossEnvironment(): void { if (!this._allowCrossEnvironment) { // error out - a deploy-time name cannot be used across environments - throw new Error(`Cannot use resource '${this.construct.path}' in a cross-environment fashion, ` + + throw new Error(`Cannot use resource '${this.node.path}' in a cross-environment fashion, ` + "the resource's physical name must be explicit set or use `PhysicalName.GENERATE_IF_NEEDED`"); } diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts index 29a139020c1b2..5a57c423779df 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts @@ -23,7 +23,7 @@ export function addStackArtifactToAssembly( // level and are not needed in the cloud assembly. // TODO: move these to the cloud assembly artifact properties instead of metadata if (stack.tags.hasTags()) { - stack.construct.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, stack.tags.renderTags()); + stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, stack.tags.renderTags()); } const deps = [ @@ -77,12 +77,12 @@ function collectStackMetadata(stack: Stack) { return; } - if (node.construct.metadata.length > 0) { + if (node.node.metadata.length > 0) { // Make the path absolute - output[ConstructNode.PATH_SEP + node.construct.path] = node.construct.metadata.map(md => stack.resolve(md) as cxschema.MetadataEntry); + output[ConstructNode.PATH_SEP + node.node.path] = node.node.metadata.map(md => stack.resolve(md) as cxschema.MetadataEntry); } - for (const child of node.construct.children) { + for (const child of node.node.children) { visit(child); } } @@ -92,11 +92,11 @@ function collectStackMetadata(stack: Stack) { return node; } - if (!node.construct.scope) { + if (!node.node.scope) { return undefined; } - return findParentStack(node.construct.scope); + return findParentStack(node.node.scope); } } diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts index dd873b6d13e6a..5a373cd3ed061 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts @@ -207,7 +207,7 @@ export class DefaultStackSynthesizer implements IStackSynthesizer { public bind(stack: Stack): void { this._stack = stack; - const qualifier = this.props.qualifier ?? stack.construct.tryGetContext(BOOTSTRAP_QUALIFIER_CONTEXT) ?? DefaultStackSynthesizer.DEFAULT_QUALIFIER; + const qualifier = this.props.qualifier ?? stack.node.tryGetContext(BOOTSTRAP_QUALIFIER_CONTEXT) ?? DefaultStackSynthesizer.DEFAULT_QUALIFIER; // Function to replace placeholders in the input string as much as possible // diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts index 850d1f08d2135..06facd881626f 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/legacy.ts @@ -102,7 +102,7 @@ export class LegacyStackSynthesizer implements IStackSynthesizer { assertBound(this.stack); // check if we have an override from context - const repositoryNameOverride = this.stack.construct.tryGetContext(ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY); + const repositoryNameOverride = this.stack.node.tryGetContext(ASSETS_ECR_REPOSITORY_NAME_OVERRIDE_CONTEXT_KEY); const repositoryName = asset.repositoryName ?? repositoryNameOverride ?? ASSETS_ECR_REPOSITORY_NAME; const imageTag = asset.sourceHash; const assetId = asset.sourceHash; @@ -121,7 +121,7 @@ export class LegacyStackSynthesizer implements IStackSynthesizer { file: asset.dockerFile, }; - this.stack.construct.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); + this.stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); this.addedImageAssets.add(assetId); } @@ -134,7 +134,7 @@ export class LegacyStackSynthesizer implements IStackSynthesizer { private doAddFileAsset(asset: FileAssetSource): FileAssetLocation { assertBound(this.stack); - let params = this.assetParameters.construct.tryFindChild(asset.sourceHash) as FileAssetParameters; + let params = this.assetParameters.node.tryFindChild(asset.sourceHash) as FileAssetParameters; if (!params) { params = new FileAssetParameters(this.assetParameters, asset.sourceHash); @@ -149,7 +149,7 @@ export class LegacyStackSynthesizer implements IStackSynthesizer { artifactHashParameter: params.artifactHashParameter.logicalId, }; - this.stack.construct.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); + this.stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.ASSET, metadata); } const bucketName = params.bucketNameParameter.valueAsString; diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index b30b008ab520d..1c7bbf4b50e07 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -168,11 +168,11 @@ export class Stack extends Construct implements ITaggable { return c; } - if (!c.construct.scope) { - throw new Error(`No stack could be identified for the construct at path ${construct.construct.path}`); + if (!c.node.scope) { + throw new Error(`No stack could be identified for the construct at path ${construct.node.path}`); } - return _lookup(c.construct.scope); + return _lookup(c.node.scope); } } @@ -359,13 +359,13 @@ export class Stack extends Construct implements ITaggable { // Also use the new behavior if we are using the new CI/CD-ready synthesizer; that way // people only have to flip one flag. // eslint-disable-next-line max-len - this.artifactId = this.construct.tryGetContext(cxapi.ENABLE_STACK_NAME_DUPLICATES_CONTEXT) || this.construct.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) + this.artifactId = this.node.tryGetContext(cxapi.ENABLE_STACK_NAME_DUPLICATES_CONTEXT) || this.node.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) ? this.generateStackArtifactId() : this.stackName; this.templateFile = `${this.artifactId}.template.json`; - this.synthesizer = props.synthesizer ?? (this.construct.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) + this.synthesizer = props.synthesizer ?? (this.node.tryGetContext(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT) ? new DefaultStackSynthesizer() : new LegacyStackSynthesizer()); this.synthesizer.bind(this); @@ -593,7 +593,7 @@ export class Stack extends Construct implements ITaggable { // denominator is 2 AZs across all AWS regions. const agnostic = Token.isUnresolved(this.account) || Token.isUnresolved(this.region); if (agnostic) { - return this.construct.tryGetContext(cxapi.AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY) || [ + return this.node.tryGetContext(cxapi.AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY) || [ Fn.select(0, Fn.getAzs()), Fn.select(1, Fn.getAzs()), ]; @@ -685,12 +685,12 @@ export class Stack extends Construct implements ITaggable { const cycle = target.stackDependencyReasons(this); if (cycle !== undefined) { // eslint-disable-next-line max-len - throw new Error(`'${target.construct.path}' depends on '${this.construct.path}' (${cycle.join(', ')}). Adding this dependency (${reason}) would create a cyclic reference.`); + throw new Error(`'${target.node.path}' depends on '${this.node.path}' (${cycle.join(', ')}). Adding this dependency (${reason}) would create a cyclic reference.`); } - let dep = this._stackDependencies[target.construct.uniqueId]; + let dep = this._stackDependencies[target.node.uniqueId]; if (!dep) { - dep = this._stackDependencies[target.construct.uniqueId] = { + dep = this._stackDependencies[target.node.uniqueId] = { stack: target, reasons: [], }; @@ -700,7 +700,7 @@ export class Stack extends Construct implements ITaggable { if (process.env.CDK_DEBUG_DEPS) { // eslint-disable-next-line no-console - console.error(`[CDK_DEBUG_DEPS] stack "${this.construct.path}" depends on "${target.construct.path}" because: ${reason}`); + console.error(`[CDK_DEBUG_DEPS] stack "${this.node.path}" depends on "${target.node.path}" because: ${reason}`); } } @@ -771,9 +771,9 @@ export class Stack extends Construct implements ITaggable { * @param cfnElement The element for which the logical ID is allocated. */ protected allocateLogicalId(cfnElement: CfnElement): string { - const scopes = cfnElement.construct.scopes; + const scopes = cfnElement.node.scopes; const stackIndex = scopes.indexOf(cfnElement.stack); - const pathComponents = scopes.slice(stackIndex + 1).map(x => x.construct.id); + const pathComponents = scopes.slice(stackIndex + 1).map(x => x.node.id); return makeUniqueId(pathComponents); } @@ -925,7 +925,7 @@ export class Stack extends Construct implements ITaggable { * Stack artifact ID is unique within the App's Cloud Assembly. */ private generateStackArtifactId() { - return this.generateStackId(this.construct.root); + return this.generateStackId(this.node.root); } /** @@ -933,7 +933,7 @@ export class Stack extends Construct implements ITaggable { */ private generateStackId(container: IConstruct | undefined) { const rootPath = rootPathTo(this, container); - const ids = rootPath.map(c => c.construct.id); + const ids = rootPath.map(c => c.node.id); // In unit tests our Stack (which is the only component) may not have an // id, so in that case just pretend it's "Stack". @@ -1050,7 +1050,7 @@ function cfnElements(node: IConstruct, into: CfnElement[] = []): CfnElement[] { into.push(node); } - for (const child of node.construct.children) { + for (const child of node.node.children) { // Don't recurse into a substack if (Stack.isStack(child)) { continue; } @@ -1066,7 +1066,7 @@ function cfnElements(node: IConstruct, into: CfnElement[] = []): CfnElement[] { * If no ancestor is given or the ancestor is not found, return the entire root path. */ export function rootPathTo(construct: IConstruct, ancestor?: IConstruct): IConstruct[] { - const scopes = construct.construct.scopes; + const scopes = construct.node.scopes; for (let i = scopes.length - 2; i >= 0; i--) { if (scopes[i] === ancestor) { return scopes.slice(i + 1); diff --git a/packages/@aws-cdk/core/lib/stage.ts b/packages/@aws-cdk/core/lib/stage.ts index fd8013cb6045b..a8a0d1d18523a 100644 --- a/packages/@aws-cdk/core/lib/stage.ts +++ b/packages/@aws-cdk/core/lib/stage.ts @@ -73,7 +73,7 @@ export class Stage extends Construct { * @experimental */ public static of(construct: IConstruct): Stage | undefined { - return construct.construct.scopes.reverse().slice(1).find(Stage.isStage); + return construct.node.scopes.reverse().slice(1).find(Stage.isStage); } /** @@ -159,8 +159,8 @@ export class Stage extends Construct { * @experimental */ public get artifactId() { - if (!this.construct.path) { return ''; } - return `assembly-${this.construct.path.replace(/\//g, '-').replace(/^-+|-+$/g, '')}`; + if (!this.node.path) { return ''; } + return `assembly-${this.node.path.replace(/\//g, '-').replace(/^-+|-+$/g, '')}`; } /** @@ -171,7 +171,7 @@ export class Stage extends Construct { */ public synth(options: StageSynthesisOptions = { }): cxapi.CloudAssembly { if (!this.assembly || options.force) { - const runtimeInfo = this.construct.tryGetContext(cxapi.DISABLE_VERSION_REPORTING) ? undefined : collectRuntimeInformation(); + const runtimeInfo = this.node.tryGetContext(cxapi.DISABLE_VERSION_REPORTING) ? undefined : collectRuntimeInformation(); this.assembly = synthesize(this, { skipValidation: options.skipValidation, runtimeInfo, @@ -191,7 +191,7 @@ export class Stage extends Construct { // to write sub-assemblies (which must happen before we actually get to this app's // synthesize() phase). return this.parentStage - ? this.parentStage._assemblyBuilder.createNestedAssembly(this.artifactId, this.construct.path) + ? this.parentStage._assemblyBuilder.createNestedAssembly(this.artifactId, this.node.path) : new cxapi.CloudAssemblyBuilder(outdir); } } diff --git a/packages/@aws-cdk/core/test/custom-resource-provider/test.custom-resource-provider.ts b/packages/@aws-cdk/core/test/custom-resource-provider/test.custom-resource-provider.ts index c13231d1eac95..ca3d8e4839241 100644 --- a/packages/@aws-cdk/core/test/custom-resource-provider/test.custom-resource-provider.ts +++ b/packages/@aws-cdk/core/test/custom-resource-provider/test.custom-resource-provider.ts @@ -23,7 +23,7 @@ export = { // The asset hash constantly changes, so in order to not have to chase it, just look // it up from the output. - const staging = stack.construct.tryFindChild('Custom:MyResourceTypeCustomResourceProvider')?.construct.tryFindChild('Staging') as AssetStaging; + const staging = stack.node.tryFindChild('Custom:MyResourceTypeCustomResourceProvider')?.node.tryFindChild('Staging') as AssetStaging; const assetHash = staging.sourceHash; const paramNames = Object.keys(cfn.Parameters); const bucketParam = paramNames[0]; diff --git a/packages/@aws-cdk/core/test/private/test.tree-metadata.ts b/packages/@aws-cdk/core/test/private/test.tree-metadata.ts index 9d3c19a811085..3ef3966b2fd95 100644 --- a/packages/@aws-cdk/core/test/private/test.tree-metadata.ts +++ b/packages/@aws-cdk/core/test/private/test.tree-metadata.ts @@ -279,9 +279,9 @@ export = { const treeArtifact = assembly.tree(); test.ok(treeArtifact); - const treenode = app.construct.findChild('Tree'); + const treenode = app.node.findChild('Tree'); - const warn = treenode.construct.metadata.find((md) => { + const warn = treenode.node.metadata.find((md) => { return md.type === cxschema.ArtifactMetadataEntryType.WARN && /Forcing an inspect error/.test(md.data as string) && /mycfnresource/.test(md.data as string); diff --git a/packages/@aws-cdk/core/test/test.app.ts b/packages/@aws-cdk/core/test/test.app.ts index 8e3cad39a7dc2..12efa5bd73edc 100644 --- a/packages/@aws-cdk/core/test/test.app.ts +++ b/packages/@aws-cdk/core/test/test.app.ts @@ -28,11 +28,11 @@ function synth(context?: { [key: string]: any }): cxapi.CloudAssembly { const c1 = new MyConstruct(stack2, 's1c2'); // add some metadata - stack1.construct.addMetadata('meta', 111); + stack1.node.addMetadata('meta', 111); Annotations.of(r2).addWarning('warning1'); Annotations.of(r2).addWarning('warning2'); - c1.construct.addMetadata('meta', { key: 'value' }); - app.construct.addMetadata('applevel', 123); // apps can also have metadata + c1.node.addMetadata('meta', { key: 'value' }); + app.node.addMetadata('applevel', 123); // apps can also have metadata }); } @@ -98,8 +98,8 @@ export = { key2: 'val2', }); const prog = new App(); - test.deepEqual(prog.construct.tryGetContext('key1'), 'val1'); - test.deepEqual(prog.construct.tryGetContext('key2'), 'val2'); + test.deepEqual(prog.node.tryGetContext('key1'), 'val1'); + test.deepEqual(prog.node.tryGetContext('key2'), 'val2'); test.done(); }, @@ -114,8 +114,8 @@ export = { key2: 'val4', }, }); - test.deepEqual(prog.construct.tryGetContext('key1'), 'val1'); - test.deepEqual(prog.construct.tryGetContext('key2'), 'val2'); + test.deepEqual(prog.node.tryGetContext('key1'), 'val1'); + test.deepEqual(prog.node.tryGetContext('key2'), 'val2'); test.done(); }, @@ -150,14 +150,14 @@ export = { foo: 'bar', }, }); - test.deepEqual(prog.construct.tryGetContext('foo'), 'bar'); + test.deepEqual(prog.node.tryGetContext('foo'), 'bar'); test.done(); }, 'setContext(k,v) cannot be called after stacks have been added because stacks may use the context'(test: Test) { const prog = new App(); new Stack(prog, 's1'); - test.throws(() => prog.construct.setContext('foo', 'bar')); + test.throws(() => prog.node.setContext('foo', 'bar')); test.done(); }, @@ -165,7 +165,7 @@ export = { class Child extends Construct { protected validate() { - return [`Error from ${this.construct.id}`]; + return [`Error from ${this.node.id}`]; } } @@ -361,9 +361,9 @@ export = { }, }); - test.ok(app.construct.tryGetContext('isString') === 'string'); - test.ok(app.construct.tryGetContext('isNumber') === 10); - test.deepEqual(app.construct.tryGetContext('isObject'), { isString: 'string', isNumber: 10 }); + test.ok(app.node.tryGetContext('isString') === 'string'); + test.ok(app.node.tryGetContext('isNumber') === 10); + test.deepEqual(app.node.tryGetContext('isObject'), { isString: 'string', isNumber: 10 }); test.done(); }, @@ -374,6 +374,6 @@ class MyConstruct extends Construct { super(scope, id); new CfnResource(this, 'r1', { type: 'ResourceType1' }); - new CfnResource(this, 'r2', { type: 'ResourceType2', properties: { FromContext: this.construct.tryGetContext('ctx1') } }); + new CfnResource(this, 'r2', { type: 'ResourceType2', properties: { FromContext: this.node.tryGetContext('ctx1') } }); } } diff --git a/packages/@aws-cdk/core/test/test.aspect.ts b/packages/@aws-cdk/core/test/test.aspect.ts index 424747fd80f55..90294a86055a7 100644 --- a/packages/@aws-cdk/core/test/test.aspect.ts +++ b/packages/@aws-cdk/core/test/test.aspect.ts @@ -21,7 +21,7 @@ class VisitOnce implements IAspect { class MyAspect implements IAspect { public visit(node: IConstruct): void { - node.construct.addMetadata('foo', 'bar'); + node.node.addMetadata('foo', 'bar'); } } @@ -45,16 +45,16 @@ export = { visit(construct: IConstruct) { Aspects.of(construct).add({ visit(inner: IConstruct) { - inner.construct.addMetadata('test', 'would-be-ignored'); + inner.node.addMetadata('test', 'would-be-ignored'); }, }); }, }); app.synth(); - test.deepEqual(root.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(root.construct.metadata[0].data, 'We detected an Aspect was added via another Aspect, and will not be applied'); + test.deepEqual(root.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(root.node.metadata[0].data, 'We detected an Aspect was added via another Aspect, and will not be applied'); // warning is not added to child construct - test.equal(child.construct.metadata.length, 0); + test.equal(child.node.metadata.length, 0); test.done(); }, @@ -64,13 +64,13 @@ export = { const child = new MyConstruct(root, 'ChildConstruct'); Aspects.of(root).add(new MyAspect()); app.synth(); - test.deepEqual(root.construct.metadata[0].type, 'foo'); - test.deepEqual(root.construct.metadata[0].data, 'bar'); - test.deepEqual(root.construct.metadata[0].type, 'foo'); - test.deepEqual(child.construct.metadata[0].data, 'bar'); + test.deepEqual(root.node.metadata[0].type, 'foo'); + test.deepEqual(root.node.metadata[0].data, 'bar'); + test.deepEqual(root.node.metadata[0].type, 'foo'); + test.deepEqual(child.node.metadata[0].data, 'bar'); // no warning is added - test.equal(root.construct.metadata.length, 1); - test.equal(child.construct.metadata.length, 1); + test.equal(root.node.metadata.length, 1); + test.equal(child.node.metadata.length, 1); test.done(); }, diff --git a/packages/@aws-cdk/core/test/test.assets.ts b/packages/@aws-cdk/core/test/test.assets.ts index a7dcfd50ed767..5f77e89db470f 100644 --- a/packages/@aws-cdk/core/test/test.assets.ts +++ b/packages/@aws-cdk/core/test/test.assets.ts @@ -16,7 +16,7 @@ export = { }); // THEN - const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.ok(assetMetadata && assetMetadata.data); @@ -83,7 +83,7 @@ export = { }); // THEN - const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.ok(assetMetadata && assetMetadata.data); @@ -111,7 +111,7 @@ export = { }); // THEN - const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.ok(assetMetadata && assetMetadata.data); @@ -131,7 +131,7 @@ export = { 'addDockerImageAsset supports overriding repository name through a context key as a workaround until we have API for that'(test: Test) { // GIVEN const stack = new Stack(); - stack.construct.setContext('assets-ecr-repository-name', 'my-custom-repo-name'); + stack.node.setContext('assets-ecr-repository-name', 'my-custom-repo-name'); // WHEN stack.addDockerImageAsset({ @@ -140,7 +140,7 @@ export = { }); // THEN - const assetMetadata = stack.construct.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); + const assetMetadata = stack.node.metadata.find(({ type }) => type === cxschema.ArtifactMetadataEntryType.ASSET); test.ok(assetMetadata && assetMetadata.data); diff --git a/packages/@aws-cdk/core/test/test.cfn-resource.ts b/packages/@aws-cdk/core/test/test.cfn-resource.ts index 7ac09497b11f7..5033af4b21598 100644 --- a/packages/@aws-cdk/core/test/test.cfn-resource.ts +++ b/packages/@aws-cdk/core/test/test.cfn-resource.ts @@ -115,7 +115,7 @@ export = nodeunit.testCase({ const r2 = new core.CfnResource(stack, 'R2', { type: 'Foo::R2' }); // also try to take a dependency on the parent of `r1` and expect the dependency not to materialize - r2.construct.addDependency(subtree); + r2.node.addDependency(subtree); // THEN - only R2 is synthesized test.deepEqual(app.synth().getStackByName(stack.stackName).template, { diff --git a/packages/@aws-cdk/core/test/test.construct.ts b/packages/@aws-cdk/core/test/test.construct.ts index fe7eae49419ae..cb128cf9e4126 100644 --- a/packages/@aws-cdk/core/test/test.construct.ts +++ b/packages/@aws-cdk/core/test/test.construct.ts @@ -9,9 +9,9 @@ import { reEnableStackTraceCollection, restoreStackTraceColection } from './util export = { 'the "Root" construct is a special construct which can be used as the root of the tree'(test: Test) { const root = new Root(); - test.equal(root.construct.id, '', 'if not specified, name of a root construct is an empty string'); - test.ok(!root.construct.scope, 'no parent'); - test.equal(root.construct.children.length, 1); + test.equal(root.node.id, '', 'if not specified, name of a root construct is an empty string'); + test.ok(!root.node.scope, 'no parent'); + test.equal(root.node.children.length, 1); test.done(); }, @@ -24,12 +24,12 @@ export = { 'construct.name returns the name of the construct'(test: Test) { const t = createTree(); - test.equal(t.child1.construct.id, 'Child1'); - test.equal(t.child2.construct.id, 'Child2'); - test.equal(t.child1_1.construct.id, 'Child11'); - test.equal(t.child1_2.construct.id, 'Child12'); - test.equal(t.child1_1_1.construct.id, 'Child111'); - test.equal(t.child2_1.construct.id, 'Child21'); + test.equal(t.child1.node.id, 'Child1'); + test.equal(t.child2.node.id, 'Child2'); + test.equal(t.child1_1.node.id, 'Child11'); + test.equal(t.child1_2.node.id, 'Child12'); + test.equal(t.child1_1_1.node.id, 'Child111'); + test.equal(t.child2_1.node.id, 'Child21'); test.done(); }, @@ -54,13 +54,13 @@ export = { 'if construct id contains path seperators, they will be replaced by double-dash'(test: Test) { const root = new Root(); const c = new Construct(root, 'Boom/Boom/Bam'); - test.deepEqual(c.construct.id, 'Boom--Boom--Bam'); + test.deepEqual(c.node.id, 'Boom--Boom--Bam'); test.done(); }, 'if "undefined" is forcefully used as an "id", it will be treated as an empty string'(test: Test) { const c = new Construct(undefined as any, undefined as any); - test.deepEqual(c.construct.id, ''); + test.deepEqual(c.node.id, ''); test.done(); }, @@ -82,17 +82,17 @@ export = { const c1 = new Construct(child2, 'My construct'); const c2 = new Construct(child1, 'My construct'); - test.deepEqual(c1.construct.path, 'This is the first child/Second level/My construct'); - test.deepEqual(c2.construct.path, 'This is the first child/My construct'); - test.deepEqual(c1.construct.uniqueId, 'ThisisthefirstchildSecondlevelMyconstruct202131E0'); - test.deepEqual(c2.construct.uniqueId, 'ThisisthefirstchildMyconstruct8C288DF9'); + test.deepEqual(c1.node.path, 'This is the first child/Second level/My construct'); + test.deepEqual(c2.node.path, 'This is the first child/My construct'); + test.deepEqual(c1.node.uniqueId, 'ThisisthefirstchildSecondlevelMyconstruct202131E0'); + test.deepEqual(c2.node.uniqueId, 'ThisisthefirstchildMyconstruct8C288DF9'); test.done(); }, 'cannot calculate uniqueId if the construct path is ["Default"]'(test: Test) { const root = new Root(); const c = new Construct(root, 'Default'); - test.throws(() => c.construct.uniqueId, /Unable to calculate a unique id for an empty set of components/); + test.throws(() => c.node.uniqueId, /Unable to calculate a unique id for an empty set of components/); test.done(); }, @@ -100,40 +100,40 @@ export = { const root = new Root(); const child = new Construct(root, 'Child1'); new Construct(root, 'Child2'); - test.equal(child.construct.children.length, 0, 'no children'); - test.equal(root.construct.children.length, 3, 'three children are expected'); + test.equal(child.node.children.length, 0, 'no children'); + test.equal(root.node.children.length, 3, 'three children are expected'); test.done(); }, 'construct.findChild(name) can be used to retrieve a child from a parent'(test: Test) { const root = new Root(); const child = new Construct(root, 'Contruct'); - test.strictEqual(root.construct.tryFindChild(child.construct.id), child, 'findChild(name) can be used to retrieve the child from a parent'); - test.ok(!root.construct.tryFindChild('NotFound'), 'findChild(name) returns undefined if the child is not found'); + test.strictEqual(root.node.tryFindChild(child.node.id), child, 'findChild(name) can be used to retrieve the child from a parent'); + test.ok(!root.node.tryFindChild('NotFound'), 'findChild(name) returns undefined if the child is not found'); test.done(); }, 'construct.getChild(name) can be used to retrieve a child from a parent'(test: Test) { const root = new Root(); const child = new Construct(root, 'Contruct'); - test.strictEqual(root.construct.findChild(child.construct.id), child, 'getChild(name) can be used to retrieve the child from a parent'); + test.strictEqual(root.node.findChild(child.node.id), child, 'getChild(name) can be used to retrieve the child from a parent'); test.throws(() => { - root.construct.findChild('NotFound'); + root.node.findChild('NotFound'); }, '', 'getChild(name) returns undefined if the child is not found'); test.done(); }, 'can remove children from the tree using tryRemoveChild()'(test: Test) { const root = new Root(); - const childrenBeforeAdding = root.construct.children.length; // Invariant to adding 'Metadata' resource or not + const childrenBeforeAdding = root.node.children.length; // Invariant to adding 'Metadata' resource or not // Add & remove const child = new Construct(root, 'Construct'); - test.equals(true, root.construct.tryRemoveChild(child.construct.id)); - test.equals(false, root.construct.tryRemoveChild(child.construct.id)); // Second time does nothing + test.equals(true, root.node.tryRemoveChild(child.node.id)); + test.equals(false, root.node.tryRemoveChild(child.node.id)); // Second time does nothing - test.equals(undefined, root.construct.tryFindChild(child.construct.id)); - test.equals(childrenBeforeAdding, root.construct.children.length); + test.equals(undefined, root.node.tryFindChild(child.node.id)); + test.equals(childrenBeforeAdding, root.node.children.length); test.done(); }, @@ -154,8 +154,8 @@ export = { }; const t = createTree(context); - test.equal(t.child1_2.construct.tryGetContext('ctx1'), 12); - test.equal(t.child1_1_1.construct.tryGetContext('ctx2'), 'hello'); + test.equal(t.child1_2.node.tryGetContext('ctx1'), 12); + test.equal(t.child1_1_1.node.tryGetContext('ctx2'), 'hello'); test.done(); }, @@ -163,34 +163,34 @@ export = { 'construct.setContext(k,v) sets context at some level and construct.getContext(key) will return the lowermost value defined in the stack'(test: Test) { const root = new Root(); const highChild = new Construct(root, 'highChild'); - highChild.construct.setContext('c1', 'root'); - highChild.construct.setContext('c2', 'root'); + highChild.node.setContext('c1', 'root'); + highChild.node.setContext('c2', 'root'); const child1 = new Construct(highChild, 'child1'); - child1.construct.setContext('c2', 'child1'); - child1.construct.setContext('c3', 'child1'); + child1.node.setContext('c2', 'child1'); + child1.node.setContext('c3', 'child1'); const child2 = new Construct(highChild, 'child2'); const child3 = new Construct(child1, 'child1child1'); - child3.construct.setContext('c1', 'child3'); - child3.construct.setContext('c4', 'child3'); + child3.node.setContext('c1', 'child3'); + child3.node.setContext('c4', 'child3'); - test.equal(highChild.construct.tryGetContext('c1'), 'root'); - test.equal(highChild.construct.tryGetContext('c2'), 'root'); - test.equal(highChild.construct.tryGetContext('c3'), undefined); + test.equal(highChild.node.tryGetContext('c1'), 'root'); + test.equal(highChild.node.tryGetContext('c2'), 'root'); + test.equal(highChild.node.tryGetContext('c3'), undefined); - test.equal(child1.construct.tryGetContext('c1'), 'root'); - test.equal(child1.construct.tryGetContext('c2'), 'child1'); - test.equal(child1.construct.tryGetContext('c3'), 'child1'); + test.equal(child1.node.tryGetContext('c1'), 'root'); + test.equal(child1.node.tryGetContext('c2'), 'child1'); + test.equal(child1.node.tryGetContext('c3'), 'child1'); - test.equal(child2.construct.tryGetContext('c1'), 'root'); - test.equal(child2.construct.tryGetContext('c2'), 'root'); - test.equal(child2.construct.tryGetContext('c3'), undefined); + test.equal(child2.node.tryGetContext('c1'), 'root'); + test.equal(child2.node.tryGetContext('c2'), 'root'); + test.equal(child2.node.tryGetContext('c3'), undefined); - test.equal(child3.construct.tryGetContext('c1'), 'child3'); - test.equal(child3.construct.tryGetContext('c2'), 'child1'); - test.equal(child3.construct.tryGetContext('c3'), 'child1'); - test.equal(child3.construct.tryGetContext('c4'), 'child3'); + test.equal(child3.node.tryGetContext('c1'), 'child3'); + test.equal(child3.node.tryGetContext('c2'), 'child1'); + test.equal(child3.node.tryGetContext('c3'), 'child1'); + test.equal(child3.node.tryGetContext('c4'), 'child3'); test.done(); }, @@ -198,29 +198,29 @@ export = { 'construct.setContext(key, value) can only be called before adding any children'(test: Test) { const root = new Root(); new Construct(root, 'child1'); - test.throws(() => root.construct.setContext('k', 'v')); + test.throws(() => root.node.setContext('k', 'v')); test.done(); }, 'fails if context key contains unresolved tokens'(test: Test) { const root = new Root(); - test.throws(() => root.construct.setContext(`my-${Aws.REGION}`, 'foo'), /Invalid context key/); - test.throws(() => root.construct.tryGetContext(Aws.REGION), /Invalid context key/); + test.throws(() => root.node.setContext(`my-${Aws.REGION}`, 'foo'), /Invalid context key/); + test.throws(() => root.node.tryGetContext(Aws.REGION), /Invalid context key/); test.done(); }, 'construct.pathParts returns an array of strings of all names from root to node'(test: Test) { const tree = createTree(); - test.deepEqual(tree.root.construct.path, ''); - test.deepEqual(tree.child1_1_1.construct.path, 'HighChild/Child1/Child11/Child111'); - test.deepEqual(tree.child2.construct.path, 'HighChild/Child2'); + test.deepEqual(tree.root.node.path, ''); + test.deepEqual(tree.child1_1_1.node.path, 'HighChild/Child1/Child11/Child111'); + test.deepEqual(tree.child2.node.path, 'HighChild/Child2'); test.done(); }, 'if a root construct has a name, it should be included in the path'(test: Test) { const tree = createTree({}); - test.deepEqual(tree.root.construct.path, ''); - test.deepEqual(tree.child1_1_1.construct.path, 'HighChild/Child1/Child11/Child111'); + test.deepEqual(tree.root.node.path, ''); + test.deepEqual(tree.child1_1_1.node.path, 'HighChild/Child1/Child11/Child111'); test.done(); }, @@ -251,31 +251,31 @@ export = { const previousValue = reEnableStackTraceCollection(); const root = new Root(); const con = new Construct(root, 'MyConstruct'); - test.deepEqual(con.construct.metadata, [], 'starts empty'); + test.deepEqual(con.node.metadata, [], 'starts empty'); - con.construct.addMetadata('key', 'value'); - con.construct.addMetadata('number', 103); - con.construct.addMetadata('array', [ 123, 456 ]); + con.node.addMetadata('key', 'value'); + con.node.addMetadata('number', 103); + con.node.addMetadata('array', [ 123, 456 ]); restoreStackTraceColection(previousValue); - test.deepEqual(con.construct.metadata[0].type, 'key'); - test.deepEqual(con.construct.metadata[0].data, 'value'); - test.deepEqual(con.construct.metadata[1].data, 103); - test.deepEqual(con.construct.metadata[2].data, [ 123, 456 ]); - test.ok(con.construct.metadata[0].trace && con.construct.metadata[0].trace[1].indexOf('FIND_ME') !== -1, 'First stack line should include this function\s name'); + test.deepEqual(con.node.metadata[0].type, 'key'); + test.deepEqual(con.node.metadata[0].data, 'value'); + test.deepEqual(con.node.metadata[1].data, 103); + test.deepEqual(con.node.metadata[2].data, [ 123, 456 ]); + test.ok(con.node.metadata[0].trace && con.node.metadata[0].trace[1].indexOf('FIND_ME') !== -1, 'First stack line should include this function\s name'); test.done(); }, 'addMetadata(type, undefined/null) is ignored'(test: Test) { const root = new Root(); const con = new Construct(root, 'Foo'); - con.construct.addMetadata('Null', null); - con.construct.addMetadata('Undefined', undefined); - con.construct.addMetadata('True', true); - con.construct.addMetadata('False', false); - con.construct.addMetadata('Empty', ''); + con.node.addMetadata('Null', null); + con.node.addMetadata('Undefined', undefined); + con.node.addMetadata('True', true); + con.node.addMetadata('False', false); + con.node.addMetadata('Empty', ''); - const exists = (key: string) => con.construct.metadata.find(x => x.type === key); + const exists = (key: string) => con.node.metadata.find(x => x.type === key); test.ok(!exists('Null')); test.ok(!exists('Undefined')); @@ -292,9 +292,9 @@ export = { Annotations.of(con).addWarning('This construct is deprecated, use the other one instead'); restoreStackTraceColection(previousValue); - test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.deepEqual(con.construct.metadata[0].data, 'This construct is deprecated, use the other one instead'); - test.ok(con.construct.metadata[0].trace && con.construct.metadata[0].trace.length > 0); + test.deepEqual(con.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); + test.deepEqual(con.node.metadata[0].data, 'This construct is deprecated, use the other one instead'); + test.ok(con.node.metadata[0].trace && con.node.metadata[0].trace.length > 0); test.done(); }, @@ -305,9 +305,9 @@ export = { Annotations.of(con).addError('Stop!'); restoreStackTraceColection(previousValue); - test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.ERROR); - test.deepEqual(con.construct.metadata[0].data, 'Stop!'); - test.ok(con.construct.metadata[0].trace && con.construct.metadata[0].trace.length > 0); + test.deepEqual(con.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.ERROR); + test.deepEqual(con.node.metadata[0].data, 'Stop!'); + test.ok(con.node.metadata[0].trace && con.node.metadata[0].trace.length > 0); test.done(); }, @@ -318,9 +318,9 @@ export = { Annotations.of(con).addInfo('Hey there, how do you do?'); restoreStackTraceColection(previousValue); - test.deepEqual(con.construct.metadata[0].type, cxschema.ArtifactMetadataEntryType.INFO); - test.deepEqual(con.construct.metadata[0].data, 'Hey there, how do you do?'); - test.ok(con.construct.metadata[0].trace && con.construct.metadata[0].trace.length > 0); + test.deepEqual(con.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.INFO); + test.deepEqual(con.node.metadata[0].data, 'Hey there, how do you do?'); + test.ok(con.node.metadata[0].trace && con.node.metadata[0].trace.length > 0); test.done(); }, @@ -330,12 +330,12 @@ export = { new MyBeautifulConstruct(root, 'mbc2'); new MyBeautifulConstruct(root, 'mbc3'); new MyBeautifulConstruct(root, 'mbc4'); - test.ok(root.construct.children.length >= 4); + test.ok(root.node.children.length >= 4); test.done(); }, // eslint-disable-next-line max-len - 'construct.validate() can be implemented to perform validation, ConstructNode.validate(construct.construct) will return all errors from the subtree (DFS)'(test: Test) { + 'construct.validate() can be implemented to perform validation, ConstructNode.validate(construct.node) will return all errors from the subtree (DFS)'(test: Test) { class MyConstruct extends Construct { protected validate() { @@ -376,7 +376,7 @@ export = { const stack = new TestStack(); - const errors = ConstructNode.validate(stack.construct).map((v: ValidationError) => ({ path: v.source.construct.path, message: v.message })); + const errors = ConstructNode.validate(stack.node).map((v: ValidationError) => ({ path: v.source.node.path, message: v.message })); // validate DFS test.deepEqual(errors, [ @@ -394,11 +394,11 @@ export = { class LockableConstruct extends Construct { public lockMe() { - (this.construct._actualNode as any)._lock(); + (this.node._actualNode as any)._lock(); } public unlockMe() { - (this.construct._actualNode as any)._unlock(); + (this.node._actualNode as any)._unlock(); } } @@ -436,23 +436,23 @@ export = { new Construct(c2, '5'); // THEN - test.deepEqual(c1.construct.findAll().map(x => x.construct.id), c1.construct.findAll(ConstructOrder.PREORDER).map(x => x.construct.id)); // default is PreOrder - test.deepEqual(c1.construct.findAll(ConstructOrder.PREORDER).map(x => x.construct.id), [ '1', '2', '4', '5', '3' ]); - test.deepEqual(c1.construct.findAll(ConstructOrder.POSTORDER).map(x => x.construct.id), [ '4', '5', '2', '3', '1' ]); + test.deepEqual(c1.node.findAll().map(x => x.node.id), c1.node.findAll(ConstructOrder.PREORDER).map(x => x.node.id)); // default is PreOrder + test.deepEqual(c1.node.findAll(ConstructOrder.PREORDER).map(x => x.node.id), [ '1', '2', '4', '5', '3' ]); + test.deepEqual(c1.node.findAll(ConstructOrder.POSTORDER).map(x => x.node.id), [ '4', '5', '2', '3', '1' ]); test.done(); }, 'ancestors returns a list of parents up to root'(test: Test) { const { child1_1_1 } = createTree(); - test.deepEqual(child1_1_1.construct.scopes.map(x => x.construct.id), [ '', 'HighChild', 'Child1', 'Child11', 'Child111' ]); + test.deepEqual(child1_1_1.node.scopes.map(x => x.node.id), [ '', 'HighChild', 'Child1', 'Child11', 'Child111' ]); test.done(); }, '"root" returns the root construct'(test: Test) { const { child1, child2, child1_1_1, root } = createTree(); - test.ok(child1.construct.root === root); - test.ok(child2.construct.root === root); - test.ok(child1_1_1.construct.root === root); + test.ok(child1.node.root === root); + test.ok(child2.node.root === root); + test.ok(child1_1_1.node.root === root); test.done(); }, @@ -463,7 +463,7 @@ export = { const defaultChild = new Construct(root, 'Resource'); new Construct(root, 'child2'); - test.same(root.construct.defaultChild, defaultChild); + test.same(root.node.defaultChild, defaultChild); test.done(); }, 'returns the child with id "Default"'(test: Test) { @@ -472,16 +472,16 @@ export = { const defaultChild = new Construct(root, 'Default'); new Construct(root, 'child2'); - test.same(root.construct.defaultChild, defaultChild); + test.same(root.node.defaultChild, defaultChild); test.done(); }, 'can override defaultChild'(test: Test) { const root = new Root(); new Construct(root, 'Resource'); const defaultChild = new Construct(root, 'OtherResource'); - root.construct.defaultChild = defaultChild; + root.node.defaultChild = defaultChild; - test.same(root.construct.defaultChild, defaultChild); + test.same(root.node.defaultChild, defaultChild); test.done(); }, 'returns "undefined" if there is no default'(test: Test) { @@ -489,7 +489,7 @@ export = { new Construct(root, 'child1'); new Construct(root, 'child2'); - test.equal(root.construct.defaultChild, undefined); + test.equal(root.node.defaultChild, undefined); test.done(); }, 'fails if there are both "Resource" and "Default"'(test: Test) { @@ -499,7 +499,7 @@ export = { new Construct(root, 'child2'); new Construct(root, 'Resource'); - test.throws(() => root.construct.defaultChild, + test.throws(() => root.node.defaultChild, /Cannot determine default child for . There is both a child with id "Resource" and id "Default"/); test.done(); @@ -511,7 +511,7 @@ function createTree(context?: any) { const root = new Root(); const highChild = new Construct(root, 'HighChild'); if (context) { - Object.keys(context).forEach(key => highChild.construct.setContext(key, context[key])); + Object.keys(context).forEach(key => highChild.node.setContext(key, context[key])); } const child1 = new Construct(highChild, 'Child1'); @@ -540,9 +540,9 @@ function toTreeString(node: IConstruct, depth = 0) { for (let i = 0; i < depth; ++i) { out += ' '; } - const name = node.construct.id || ''; + const name = node.node.id || ''; out += `${node.constructor.name}${name.length > 0 ? ' [' + name + ']' : ''}\n`; - for (const child of node.construct.children) { + for (const child of node.node.children) { out += toTreeString(child, depth + 1); } return out; diff --git a/packages/@aws-cdk/core/test/test.context.ts b/packages/@aws-cdk/core/test/test.context.ts index 4e4bffc743010..b19c2514b1786 100644 --- a/packages/@aws-cdk/core/test/test.context.ts +++ b/packages/@aws-cdk/core/test/test.context.ts @@ -18,7 +18,7 @@ export = { test.deepEqual(before, [ 'dummy1a', 'dummy1b', 'dummy1c' ]); const key = expectedContextKey(stack); - stack.construct.setContext(key, ['us-east-1a', 'us-east-1b']); + stack.node.setContext(key, ['us-east-1a', 'us-east-1b']); const azs = stack.availabilityZones; test.deepEqual(azs, ['us-east-1a', 'us-east-1b']); @@ -32,7 +32,7 @@ export = { test.deepEqual(before, [ 'dummy1a', 'dummy1b', 'dummy1c' ]); const key = expectedContextKey(stack); - stack.construct.setContext(key, 'not-a-list'); + stack.node.setContext(key, 'not-a-list'); test.throws( () => stack.availabilityZones, @@ -149,7 +149,7 @@ export = { // NOTE: error key is inlined here because it's part of the CX-API // compatibility surface. - stack.construct.setContext(contextKey, { $providerError: 'I had a boo-boo' }); + stack.node.setContext(contextKey, { $providerError: 'I had a boo-boo' }); const construct = new Construct(stack, 'Child'); // Verify that we got the right hardcoded key above, give a descriptive error if not @@ -162,7 +162,7 @@ export = { }); // THEN - const error = construct.construct.metadata.find(m => m.type === 'aws:cdk:error'); + const error = construct.node.metadata.find(m => m.type === 'aws:cdk:error'); test.equals(error && error.data, 'I had a boo-boo'); test.done(); diff --git a/packages/@aws-cdk/core/test/test.logical-id.ts b/packages/@aws-cdk/core/test/test.logical-id.ts index 3a804f26c19ed..332dad2f14eba 100644 --- a/packages/@aws-cdk/core/test/test.logical-id.ts +++ b/packages/@aws-cdk/core/test/test.logical-id.ts @@ -209,7 +209,7 @@ export = { const ref = c1.ref; const c2 = new CfnResource(stack, 'Construct2', { type: 'R2', properties: { ReferenceToR1: ref } }); - c2.construct.addDependency(c1); + c2.node.addDependency(c1); // THEN test.deepEqual(toCloudFormation(stack), { @@ -229,8 +229,8 @@ export = { 'customize logical id allocation behavior by overriding `Stack.allocateLogicalId`'(test: Test) { class MyStack extends Stack { protected allocateLogicalId(element: CfnElement): string { - if (element.construct.id === 'A') { return 'LogicalIdOfA'; } - if (element.construct.id === 'B') { return 'LogicalIdOfB'; } + if (element.node.id === 'A') { return 'LogicalIdOfA'; } + if (element.node.id === 'B') { return 'LogicalIdOfB'; } throw new Error('Invalid element ID'); } } diff --git a/packages/@aws-cdk/core/test/test.resource.ts b/packages/@aws-cdk/core/test/test.resource.ts index 6f2612f45b81d..bebaf2e8be1a8 100644 --- a/packages/@aws-cdk/core/test/test.resource.ts +++ b/packages/@aws-cdk/core/test/test.resource.ts @@ -129,8 +129,8 @@ export = { const r1 = new Counter(stack, 'Counter1', { Count: 1 }); const r2 = new Counter(stack, 'Counter2', { Count: 1 }); const r3 = new CfnResource(stack, 'Resource3', { type: 'MyResourceType' }); - r2.construct.addDependency(r1); - r2.construct.addDependency(r3); + r2.node.addDependency(r1); + r2.node.addDependency(r3); synthesize(stack); @@ -357,8 +357,8 @@ export = { const c3 = new C3(stack, 'MyC3'); const dependingResource = new CfnResource(stack, 'MyResource', { type: 'R' }); - dependingResource.construct.addDependency(c1, c2); - dependingResource.construct.addDependency(c3); + dependingResource.node.addDependency(c1, c2); + dependingResource.node.addDependency(c3); synthesize(stack); @@ -642,7 +642,7 @@ export = { '"aws:cdk:path" metadata is added if "aws:cdk:path-metadata" context is set to true'(test: Test) { const stack = new Stack(); - stack.construct.setContext(cxapi.PATH_METADATA_ENABLE_CONTEXT, true); + stack.node.setContext(cxapi.PATH_METADATA_ENABLE_CONTEXT, true); const parent = new Construct(stack, 'Parent'); @@ -667,7 +667,7 @@ export = { const resB = new CfnResource(stackB, 'Resource', { type: 'R' }); // WHEN - resB.construct.addDependency(resA); + resB.node.addDependency(resA); // THEN const assembly = app.synth(); @@ -681,7 +681,7 @@ export = { }, }, }); - test.deepEqual(stackB.dependencies.map(s => s.construct.id), ['StackA']); + test.deepEqual(stackB.dependencies.map(s => s.node.id), ['StackA']); test.done(); }, diff --git a/packages/@aws-cdk/core/test/test.stack.ts b/packages/@aws-cdk/core/test/test.stack.ts index b24717886a5b0..f92d2d9512b1d 100644 --- a/packages/@aws-cdk/core/test/test.stack.ts +++ b/packages/@aws-cdk/core/test/test.stack.ts @@ -129,9 +129,9 @@ export = { const o = new CfnOutput(stack, 'MyOutput', { value: 'boom' }); const c = new CfnCondition(stack, 'MyCondition'); - test.equal(stack.construct.findChild(p.construct.id), p); - test.equal(stack.construct.findChild(o.construct.id), o); - test.equal(stack.construct.findChild(c.construct.id), c); + test.equal(stack.node.findChild(p.node.id), p); + test.equal(stack.node.findChild(o.node.id), o); + test.equal(stack.node.findChild(c.node.id), c); test.done(); }, @@ -583,7 +583,7 @@ export = { app.synth(); // THEN - test.deepEqual(stack2.dependencies.map(s => s.construct.id), ['Stack1']); + test.deepEqual(stack2.dependencies.map(s => s.node.id), ['Stack1']); test.done(); }, @@ -859,7 +859,7 @@ export = { const child = new Stack(parent, 'child'); // WHEN - child.construct.addMetadata('foo', 'bar'); + child.node.addMetadata('foo', 'bar'); // THEN const asm = app.synth(); diff --git a/packages/@aws-cdk/core/test/test.stage.ts b/packages/@aws-cdk/core/test/test.stage.ts index 42ddf9fb8972d..d93b8d2c08c38 100644 --- a/packages/@aws-cdk/core/test/test.stage.ts +++ b/packages/@aws-cdk/core/test/test.stage.ts @@ -152,7 +152,7 @@ export = { // THEN app.synth(); - test.deepEqual(aspect.visits.map(c => c.construct.path), [ + test.deepEqual(aspect.visits.map(c => c.node.path), [ 'MyStage/Stack', 'MyStage/Stack/Resource', ]); @@ -172,7 +172,7 @@ export = { // THEN app.synth(); - test.deepEqual(aspect.visits.map(c => c.construct.path), [ + test.deepEqual(aspect.visits.map(c => c.node.path), [ '', 'Tree', ]); @@ -301,4 +301,4 @@ class BogusStack extends Stack { function acctRegion(s: Stack) { return [s.account, s.region]; -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/test/test.staging.ts b/packages/@aws-cdk/core/test/test.staging.ts index 434422fc949c8..5b944e8976d1b 100644 --- a/packages/@aws-cdk/core/test/test.staging.ts +++ b/packages/@aws-cdk/core/test/test.staging.ts @@ -47,7 +47,7 @@ export = { 'staging can be disabled through context'(test: Test) { // GIVEN const stack = new Stack(); - stack.construct.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); + stack.node.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); const sourcePath = path.join(__dirname, 'fs', 'fixtures', 'test1'); // WHEN diff --git a/packages/@aws-cdk/core/test/test.synthesis.ts b/packages/@aws-cdk/core/test/test.synthesis.ts index 7fde8510f398f..d83ba978bdaa3 100644 --- a/packages/@aws-cdk/core/test/test.synthesis.ts +++ b/packages/@aws-cdk/core/test/test.synthesis.ts @@ -153,7 +153,7 @@ export = { } const root = new SynthesizeMe(); - const assembly = cdk.ConstructNode.synth(root.construct, { outdir: fs.mkdtempSync(path.join(os.tmpdir(), 'outdir')) }); + const assembly = cdk.ConstructNode.synth(root.node, { outdir: fs.mkdtempSync(path.join(os.tmpdir(), 'outdir')) }); test.deepEqual(calls, [ 'prepare', 'validate', 'synthesize' ]); const stack = assembly.getStackByName('art'); diff --git a/packages/@aws-cdk/core/test/test.util.ts b/packages/@aws-cdk/core/test/test.util.ts index 986f10a5a1d1c..010f6ef33dc5b 100644 --- a/packages/@aws-cdk/core/test/test.util.ts +++ b/packages/@aws-cdk/core/test/test.util.ts @@ -96,7 +96,7 @@ export = testCase({ test.done(); function path(s: Stack) { - return pathToTopLevelStack(s).map(x => x.construct.id); + return pathToTopLevelStack(s).map(x => x.node.id); } }, @@ -132,7 +132,7 @@ export = testCase({ function lca(s1: Stack, s2: Stack) { const res = findLastCommonElement(pathToTopLevelStack(s1), pathToTopLevelStack(s2)); if (!res) { return undefined; } - return res.construct.id; + return res.node.id; } }, }); diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts index 3c3d7d8c42568..01759f71b7e45 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts @@ -147,7 +147,7 @@ export class Provider extends Construct implements cfn.ICustomResourceProvider { private createFunction(entrypoint: string) { const fn = new lambda.Function(this, `framework-${entrypoint}`, { code: lambda.Code.fromAsset(RUNTIME_HANDLER_PATH), - description: `AWS CDK resource provider framework - ${entrypoint} (${this.construct.path})`.slice(0, 256), + description: `AWS CDK resource provider framework - ${entrypoint} (${this.node.path})`.slice(0, 256), runtime: lambda.Runtime.NODEJS_10_X, handler: `framework.${entrypoint}`, timeout: FRAMEWORK_HANDLER_TIMEOUT, diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts index 9672810518f71..f35bce528d366 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/waiter-state-machine.ts @@ -87,7 +87,7 @@ export class WaiterStateMachine extends Construct { RoleArn: role.roleArn, }, }); - resource.construct.addDependency(role); + resource.node.addDependency(role); this.stateMachineArn = resource.ref; } diff --git a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.ts b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.ts index ddce585cb4a1b..3b241031e04c1 100644 --- a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.ts +++ b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/integ.aws-custom-resource.ts @@ -33,7 +33,7 @@ const listTopics = new AwsCustomResource(stack, 'ListTopics', { }, policy: AwsCustomResourcePolicy.fromSdkCalls({resources: AwsCustomResourcePolicy.ANY_RESOURCE}), }); -listTopics.construct.addDependency(topic); +listTopics.node.addDependency(topic); const ssmParameter = new ssm.StringParameter(stack, 'DummyParameter', { stringValue: '1337', diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts index 6fe85db543230..01ccd37e89d89 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integ.provider.ts @@ -30,7 +30,7 @@ class TestStack extends Stack { }); // delay file2 updates so we can test async assertions - file2.construct.addDependency(file1); + file2.node.addDependency(file1); new CfnOutput(this, 'file1-url', { value: file1.url }); new CfnOutput(this, 'file2-url', { value: file2.url }); diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-assert.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-assert.ts index 4b06558fc1f8b..0823d21e05e51 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-assert.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-assert.ts @@ -54,7 +54,7 @@ class S3AssertProvider extends Construct { public static getOrCreate(scope: Construct) { const providerId = 'com.amazonaws.cdk.custom-resources.s3assert-provider'; const stack = Stack.of(scope); - const group = stack.construct.tryFindChild(providerId) as S3AssertProvider || new S3AssertProvider(stack, providerId); + const group = stack.node.tryFindChild(providerId) as S3AssertProvider || new S3AssertProvider(stack, providerId); return group.provider.serviceToken; } diff --git a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts index ca689a41df832..234ec567cbdbb 100644 --- a/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts +++ b/packages/@aws-cdk/custom-resources/test/provider-framework/integration-test-fixtures/s3-file.ts @@ -65,7 +65,7 @@ class S3FileProvider extends Construct { public static getOrCreate(scope: Construct) { const stack = Stack.of(scope); const id = 'com.amazonaws.cdk.custom-resources.s3file-provider'; - const x = stack.construct.tryFindChild(id) as S3FileProvider || new S3FileProvider(stack, id); + const x = stack.node.tryFindChild(id) as S3FileProvider || new S3FileProvider(stack, id); return x.provider.serviceToken; } diff --git a/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts b/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts index c22e99b13bd08..c13dad054c790 100644 --- a/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts +++ b/packages/@aws-cdk/pipelines/lib/actions/deploy-cdk-stack-action.ts @@ -270,10 +270,10 @@ function roleFromPlaceholderArn(scope: Construct, arn: string | undefined): iam. scope = hackyRoleScope(scope, arn); // https://github.com/aws/aws-cdk/issues/7255 - let existingRole = scope.construct.tryFindChild(`ImmutableRole${id}`) as iam.IRole; + let existingRole = scope.node.tryFindChild(`ImmutableRole${id}`) as iam.IRole; if (existingRole) { return existingRole; } // For when #7255 is fixed. - existingRole = scope.construct.tryFindChild(id) as iam.IRole; + existingRole = scope.node.tryFindChild(id) as iam.IRole; if (existingRole) { return existingRole; } return iam.Role.fromRoleArn(scope, id, cfnExpressionFromManifestString(arn), { mutable: false }); diff --git a/packages/@aws-cdk/pipelines/lib/pipeline.ts b/packages/@aws-cdk/pipelines/lib/pipeline.ts index e565c0271881e..f20021b34d1a8 100644 --- a/packages/@aws-cdk/pipelines/lib/pipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/pipeline.ts @@ -65,7 +65,7 @@ export class CdkPipeline extends Construct { constructor(scope: Construct, id: string, props: CdkPipelineProps) { super(scope, id); - if (!App.isApp(this.construct.root)) { + if (!App.isApp(this.node.root)) { throw new Error('CdkPipeline must be created under an App'); } @@ -103,7 +103,7 @@ export class CdkPipeline extends Construct { projectName: maybeSuffix(props.pipelineName, '-publish'), }); - this.construct.applyAspect({ visit: () => this._assets.removeAssetsStageIfEmpty() }); + this.node.applyAspect({ visit: () => this._assets.removeAssetsStageIfEmpty() }); } /** @@ -195,7 +195,7 @@ export class CdkPipeline extends Construct { const depAction = stackActions.find(s => s.stackArtifactId === depId); if (depAction === undefined) { - this.construct.addWarning(`Stack '${stackAction.stackName}' depends on stack ` + + this.node.addWarning(`Stack '${stackAction.stackName}' depends on stack ` + `'${depId}', but that dependency is not deployed through the pipeline!`); } else if (!(depAction.executeRunOrder < stackAction.prepareRunOrder)) { yield `Stack '${stackAction.stackName}' depends on stack ` + diff --git a/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts b/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts index 83b40ae2fbdf2..7fc07f8d30fa5 100644 --- a/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts +++ b/packages/@aws-cdk/pipelines/lib/private/construct-internals.ts @@ -6,10 +6,10 @@ import { App, IConstruct, Stage } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; export function appOf(construct: IConstruct): App { - const root = construct.construct.root; + const root = construct.node.root; if (!App.isApp(root)) { - throw new Error(`Construct must be created under an App, but is not: ${construct.construct.path}`); + throw new Error(`Construct must be created under an App, but is not: ${construct.node.path}`); } return root; diff --git a/packages/@aws-cdk/pipelines/lib/stage.ts b/packages/@aws-cdk/pipelines/lib/stage.ts index 994c6f2097224..dd5aa28c5e50e 100644 --- a/packages/@aws-cdk/pipelines/lib/stage.ts +++ b/packages/@aws-cdk/pipelines/lib/stage.ts @@ -55,7 +55,7 @@ export class CdkStage extends Construct { this.cloudAssemblyArtifact = props.cloudAssemblyArtifact; this.host = props.host; - this.construct.applyAspect({ visit: () => this.prepareStage() }); + this.node.applyAspect({ visit: () => this.prepareStage() }); } /** diff --git a/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts b/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts index 3e9f2d7b09c29..71717c4dbb1a7 100644 --- a/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts +++ b/packages/@aws-cdk/pipelines/test/cross-environment-infra.test.ts @@ -26,7 +26,7 @@ test('in a cross-account/cross-region setup, artifact bucket can be read by depl // THEN app.synth(); - const supportStack = app.construct.findAll().filter(Stack.isStack).find(s => s.stackName === 'PipelineStack-support-us-elsewhere'); + const supportStack = app.node.findAll().filter(Stack.isStack).find(s => s.stackName === 'PipelineStack-support-us-elsewhere'); expect(supportStack).not.toBeUndefined(); expect(supportStack).toHaveResourceLike('AWS::S3::BucketPolicy', { diff --git a/packages/decdk/lib/declarative-stack.ts b/packages/decdk/lib/declarative-stack.ts index 47b929861c66d..8b937ecd3525e 100644 --- a/packages/decdk/lib/declarative-stack.ts +++ b/packages/decdk/lib/declarative-stack.ts @@ -383,9 +383,9 @@ function invokeMethod(stack: cdk.Stack, method: reflect.Callable, parameters: an */ function deconstructGetAtt(stack: cdk.Stack, id: string, attribute: string) { return cdk.Lazy.stringValue({ produce: () => { - const res = stack.construct.tryFindChild(id); + const res = stack.node.tryFindChild(id); if (!res) { - const include = stack.construct.tryFindChild('Include') as cdk.CfnInclude; + const include = stack.node.tryFindChild('Include') as cdk.CfnInclude; if (!include) { throw new Error(`Unexpected - "Include" should be in the stack at this point`); } @@ -403,7 +403,7 @@ function deconstructGetAtt(stack: cdk.Stack, id: string, attribute: string) { } function findConstruct(stack: cdk.Stack, id: string) { - const child = stack.construct.tryFindChild(id); + const child = stack.node.tryFindChild(id); if (!child) { throw new Error(`Construct with ID ${id} not found (it must be defined before it is referenced)`); } @@ -411,7 +411,7 @@ function findConstruct(stack: cdk.Stack, id: string) { } function processReferences(stack: cdk.Stack) { - const include = stack.construct.findChild('Include') as cdk.CfnInclude; + const include = stack.node.findChild('Include') as cdk.CfnInclude; if (!include) { throw new Error('Unexpected'); } From d04d538b154f5db711c89e3dce3801d880ba445c Mon Sep 17 00:00:00 2001 From: AWS CDK Team Date: Wed, 12 Aug 2020 16:53:49 +0000 Subject: [PATCH 37/43] chore(release): 1.58.0 --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ lerna.json | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e69649d4564b..9377e85b14174 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,40 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.58.0](https://github.com/aws/aws-cdk/compare/v1.57.0...v1.58.0) (2020-08-12) + + +### Features + +* **cloudwatch:** alarm status widget ([#9456](https://github.com/aws/aws-cdk/issues/9456)) ([41940d3](https://github.com/aws/aws-cdk/commit/41940d3cfad289cbaed8ff60a21c6c9fa9aad532)) +* **cognito:** better control sms role creation ([#9513](https://github.com/aws/aws-cdk/issues/9513)) ([a772fe8](https://github.com/aws/aws-cdk/commit/a772fe84784e62843ef724a9158fc8cda848c5c9)), closes [#6943](https://github.com/aws/aws-cdk/issues/6943) +* **core:** deprecate "Construct.node" in favor of "Construct.construct" ([#9557](https://github.com/aws/aws-cdk/issues/9557)) ([aa4c5b7](https://github.com/aws/aws-cdk/commit/aa4c5b7df3a4880638361026ec0f6a77b7476b40)), closes [/github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#10](https://github.com/aws//github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md/issues/10) +* **core:** local bundling provider ([#9564](https://github.com/aws/aws-cdk/issues/9564)) ([3da0aa9](https://github.com/aws/aws-cdk/commit/3da0aa99d16e908a39f43f463ac2889dd232c611)) +* **core:** new annotations api ([#9563](https://github.com/aws/aws-cdk/issues/9563)) ([ae9ed62](https://github.com/aws/aws-cdk/commit/ae9ed6208dc81a7a38f4b9626c7c30f1811f97a9)), closes [/github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#09](https://github.com/aws//github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md/issues/09) +* **core:** new APIs for Aspects and Tags ([#9558](https://github.com/aws/aws-cdk/issues/9558)) ([a311428](https://github.com/aws/aws-cdk/commit/a311428d6013a1486585979a010f4105b0e0f97a)), closes [/github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#02](https://github.com/aws//github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md/issues/02) +* **ecs:** Option to encrypt lifecycle hook SNS Topic ([#9343](https://github.com/aws/aws-cdk/issues/9343)) ([38aad67](https://github.com/aws/aws-cdk/commit/38aad67c5d2db21cfb3660c1574f7fedde9860dc)) +* **events:** use existing Role when running ECS Task ([#8145](https://github.com/aws/aws-cdk/issues/8145)) ([aad951a](https://github.com/aws/aws-cdk/commit/aad951ae5355391463d9af2a49cd890f8d78f2d0)), closes [#7859](https://github.com/aws/aws-cdk/issues/7859) +* **global-accelerator:** referencing Global Accelerator security group ([#9358](https://github.com/aws/aws-cdk/issues/9358)) ([1fe9684](https://github.com/aws/aws-cdk/commit/1fe9684ea6b2dcaac1d97b64edfd4ef87cc65c0f)) +* **iam:** validate policies for missing resources/principals ([#9269](https://github.com/aws/aws-cdk/issues/9269)) ([60d01b1](https://github.com/aws/aws-cdk/commit/60d01b132b0e76224f7aae6b6caad5d13e7a816b)), closes [#7615](https://github.com/aws/aws-cdk/issues/7615) +* **lambda:** autoscaling for lambda aliases ([#8883](https://github.com/aws/aws-cdk/issues/8883)) ([d9d9b90](https://github.com/aws/aws-cdk/commit/d9d9b908ca149b189f0e1bde7df0d75afd5b26ff)) +* **readme:** include partitions.io cdk board in "getting help" ([#9541](https://github.com/aws/aws-cdk/issues/9541)) ([f098014](https://github.com/aws/aws-cdk/commit/f098014e0e9e49b2cc6a30922b8b0545e9c45e5e)) +* "stack relative exports" flag ([#9604](https://github.com/aws/aws-cdk/issues/9604)) ([398f872](https://github.com/aws/aws-cdk/commit/398f8720fac6ae7eb663a36c87c1f8f11aa89045)) +* **secretsmanager:** Specify secret value at creation ([#9594](https://github.com/aws/aws-cdk/issues/9594)) ([07fedff](https://github.com/aws/aws-cdk/commit/07fedffadf3900d754b5df5a24cc84622299ede4)), closes [#5810](https://github.com/aws/aws-cdk/issues/5810) + + +### Bug Fixes + +* **cfn-include:** allowedValues aren't included when specified by a parameter ([#9532](https://github.com/aws/aws-cdk/issues/9532)) ([e7dc82f](https://github.com/aws/aws-cdk/commit/e7dc82f04d83a7c85131e11e258f3ab031e61eda)) +* **codedeploy:** ServerDeploymentGroup takes AutoScalingGroup instead of IAutoScalingGroup ([#9252](https://github.com/aws/aws-cdk/issues/9252)) ([9ff55ae](https://github.com/aws/aws-cdk/commit/9ff55aeeed49d89bf13b2baf9025a1f4e038aa43)), closes [#9175](https://github.com/aws/aws-cdk/issues/9175) +* **docdb:** `autoMinorVersionUpgrade` property was not set to `true` by default as stated in the docstring ([#9505](https://github.com/aws/aws-cdk/issues/9505)) ([e878f9c](https://github.com/aws/aws-cdk/commit/e878f9c5fd503615a4d65a3f866e80cff001a309)) +* **ec2:** Volume grants have an overly complicated API ([#9115](https://github.com/aws/aws-cdk/issues/9115)) ([74e8391](https://github.com/aws/aws-cdk/commit/74e839189b2e9b028e6b9944884bf8fe73de2429)), closes [#9114](https://github.com/aws/aws-cdk/issues/9114) +* **efs:** LifecyclePolicy of AFTER_7_DAYS is not applied ([#9475](https://github.com/aws/aws-cdk/issues/9475)) ([f78c346](https://github.com/aws/aws-cdk/commit/f78c3469522006d38078db6effc4556d44da9747)), closes [#9474](https://github.com/aws/aws-cdk/issues/9474) +* **eks:** clusters in a FAILED state are not detected ([#9553](https://github.com/aws/aws-cdk/issues/9553)) ([d651948](https://github.com/aws/aws-cdk/commit/d651948b4b4ef43fedbaba69905e860fd595513d)) +* **eks:** private endpoint access doesn't work with `Vpc.fromLookup` ([#9544](https://github.com/aws/aws-cdk/issues/9544)) ([dd0f4cb](https://github.com/aws/aws-cdk/commit/dd0f4cb55bd9d7a95ccc9691ba33dab658d60e97)), closes [#9542](https://github.com/aws/aws-cdk/issues/9542) [#5383](https://github.com/aws/aws-cdk/issues/5383) +* **lambda:** cannot create lambda in public subnets ([#9468](https://github.com/aws/aws-cdk/issues/9468)) ([b46fdc9](https://github.com/aws/aws-cdk/commit/b46fdc92d3c3cee269bfa7785fa78679aa781880)) +* **pipelines:** CodeBuild images have (too) old Node version ([#9446](https://github.com/aws/aws-cdk/issues/9446)) ([bd45f34](https://github.com/aws/aws-cdk/commit/bd45f3419e24d6a9d9989a0efeacf2233866100b)), closes [#9070](https://github.com/aws/aws-cdk/issues/9070) +* **pipelines:** manual approval of changeset uses wrong ordering ([#9508](https://github.com/aws/aws-cdk/issues/9508)) ([5c01da8](https://github.com/aws/aws-cdk/commit/5c01da8d82f77e0241890101258aace2dac1902d)), closes [#9101](https://github.com/aws/aws-cdk/issues/9101) [#9101](https://github.com/aws/aws-cdk/issues/9101) + ## [1.57.0](https://github.com/aws/aws-cdk/compare/v1.56.0...v1.57.0) (2020-08-07) diff --git a/lerna.json b/lerna.json index 96e8ea36e52af..51753d20a7b8a 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "tools/*" ], "rejectCycles": "true", - "version": "1.57.0" + "version": "1.58.0" } From 0d915311a4e082362bb2b5165d91664d8afacb3f Mon Sep 17 00:00:00 2001 From: Neta Nir Date: Wed, 12 Aug 2020 10:09:08 -0700 Subject: [PATCH 38/43] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9377e85b14174..d445eaaa302df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,8 @@ All notable changes to this project will be documented in this file. See [standa * **cognito:** better control sms role creation ([#9513](https://github.com/aws/aws-cdk/issues/9513)) ([a772fe8](https://github.com/aws/aws-cdk/commit/a772fe84784e62843ef724a9158fc8cda848c5c9)), closes [#6943](https://github.com/aws/aws-cdk/issues/6943) * **core:** deprecate "Construct.node" in favor of "Construct.construct" ([#9557](https://github.com/aws/aws-cdk/issues/9557)) ([aa4c5b7](https://github.com/aws/aws-cdk/commit/aa4c5b7df3a4880638361026ec0f6a77b7476b40)), closes [/github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#10](https://github.com/aws//github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md/issues/10) * **core:** local bundling provider ([#9564](https://github.com/aws/aws-cdk/issues/9564)) ([3da0aa9](https://github.com/aws/aws-cdk/commit/3da0aa99d16e908a39f43f463ac2889dd232c611)) -* **core:** new annotations api ([#9563](https://github.com/aws/aws-cdk/issues/9563)) ([ae9ed62](https://github.com/aws/aws-cdk/commit/ae9ed6208dc81a7a38f4b9626c7c30f1811f97a9)), closes [/github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#09](https://github.com/aws//github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md/issues/09) -* **core:** new APIs for Aspects and Tags ([#9558](https://github.com/aws/aws-cdk/issues/9558)) ([a311428](https://github.com/aws/aws-cdk/commit/a311428d6013a1486585979a010f4105b0e0f97a)), closes [/github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#02](https://github.com/aws//github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md/issues/02) +* **core:** new annotations api ([#9563](https://github.com/aws/aws-cdk/issues/9563)) ([ae9ed62](https://github.com/aws/aws-cdk/commit/ae9ed6208dc81a7a38f4b9626c7c30f1811f97a9)), closes [/github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#09](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#09-logging-logging-api-changes) +* **core:** new APIs for Aspects and Tags ([#9558](https://github.com/aws/aws-cdk/issues/9558)) ([a311428](https://github.com/aws/aws-cdk/commit/a311428d6013a1486585979a010f4105b0e0f97a)), closes [/github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#02](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0192-remove-constructs-compat.md#02-aspects-changes-in-aspects-api) * **ecs:** Option to encrypt lifecycle hook SNS Topic ([#9343](https://github.com/aws/aws-cdk/issues/9343)) ([38aad67](https://github.com/aws/aws-cdk/commit/38aad67c5d2db21cfb3660c1574f7fedde9860dc)) * **events:** use existing Role when running ECS Task ([#8145](https://github.com/aws/aws-cdk/issues/8145)) ([aad951a](https://github.com/aws/aws-cdk/commit/aad951ae5355391463d9af2a49cd890f8d78f2d0)), closes [#7859](https://github.com/aws/aws-cdk/issues/7859) * **global-accelerator:** referencing Global Accelerator security group ([#9358](https://github.com/aws/aws-cdk/issues/9358)) ([1fe9684](https://github.com/aws/aws-cdk/commit/1fe9684ea6b2dcaac1d97b64edfd4ef87cc65c0f)) From cc229c2c660e7e5be2255f031c001218c26b4752 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Wed, 12 Aug 2020 19:08:58 +0100 Subject: [PATCH 39/43] fix(cloudfront): Escape hatch support for Distribution (#9648) Changed the ID for the CfnDistribution to support escape hatches (`dist.node.defaultChild`). fixes #9620 BREAKING CHANGE: (cloudfront) Changed IDs for Distributions (will cause resource replacement). ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../test/integ.http-origin.expected.json | 2 +- .../integ.load-balancer-origin.expected.json | 4 ++-- .../test/integ.origin-group.expected.json | 4 ++-- .../test/integ.s3-origin.expected.json | 2 +- .../aws-cloudfront/lib/distribution.ts | 2 +- .../aws-cloudfront/test/distribution.test.ts | 18 ++++++++++++++++++ 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.http-origin.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.http-origin.expected.json index c5f7da26599c6..34b8f67a5b66f 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.http-origin.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.http-origin.expected.json @@ -1,6 +1,6 @@ { "Resources": { - "DistributionCFDistribution882A7313": { + "Distribution830FAC52": { "Type": "AWS::CloudFront::Distribution", "Properties": { "DistributionConfig": { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.load-balancer-origin.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.load-balancer-origin.expected.json index 8c97abc155066..1b83e071d6275 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.load-balancer-origin.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.load-balancer-origin.expected.json @@ -400,7 +400,7 @@ } } }, - "DistributionCFDistribution882A7313": { + "Distribution830FAC52": { "Type": "AWS::CloudFront::Distribution", "Properties": { "DistributionConfig": { @@ -430,4 +430,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json index 6ed3596c52eba..21d939154cff2 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json @@ -64,7 +64,7 @@ } } }, - "DistributionCFDistribution882A7313": { + "Distribution830FAC52": { "Type": "AWS::CloudFront::Distribution", "Properties": { "DistributionConfig": { @@ -141,4 +141,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json index 173044c7a0dab..919d482d8b880 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json @@ -64,7 +64,7 @@ } } }, - "DistributionCFDistribution882A7313": { + "Distribution830FAC52": { "Type": "AWS::CloudFront::Distribution", "Properties": { "DistributionConfig": { diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index 81cb0e7470ec4..48300b3faae83 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -158,7 +158,7 @@ export class Distribution extends Resource implements IDistribution { this.certificate = props.certificate; this.errorResponses = props.errorResponses ?? []; - const distribution = new CfnDistribution(this, 'CFDistribution', { distributionConfig: { + const distribution = new CfnDistribution(this, 'Resource', { distributionConfig: { enabled: true, origins: Lazy.anyValue({ produce: () => this.renderOrigins() }), originGroups: Lazy.anyValue({ produce: () => this.renderOriginGroups() }), diff --git a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts index 29942711ff781..60275f1cf07d0 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts @@ -382,6 +382,24 @@ test('price class is included if provided', () => { }); }); +test('escape hatches are supported', () => { + const dist = new Distribution(stack, 'Dist', { + defaultBehavior: { origin: defaultOrigin }, + }); + const cfnDist = dist.node.defaultChild as CfnDistribution; + cfnDist.addPropertyOverride('DistributionConfig.DefaultCacheBehavior.ForwardedValues.Headers', ['*']); + + expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + DistributionConfig: { + DefaultCacheBehavior: { + ForwardedValues: { + Headers: ['*'], + }, + }, + }, + }); +}); + function defaultOrigin(domainName?: string): IOrigin { return new TestOrigin(domainName ?? 'www.example.com'); } From b1b4ceee16a2483604fa97741ed2f7ddf340d10a Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Wed, 12 Aug 2020 11:32:06 -0700 Subject: [PATCH 40/43] feat(codebuild): add support for GPU build images (#8879) CodeBuild has added support for running builds on machines with GPU drivers. This required some changes to the protocol between `IBuildImage` and `Project`, as those images are hosted in a public ECR repository that the image must grant the Project's Role access to. Introduced a `bind()` method to `IBuildImage` - to maintain backwards comaptibility, made it optional. Fixes #8408 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-codebuild/README.md | 34 +++ packages/@aws-cdk/aws-codebuild/lib/index.ts | 1 + .../lib/linux-gpu-build-image.ts | 141 +++++++++ .../private/run-script-linux-build-spec.ts | 32 ++ .../@aws-cdk/aws-codebuild/lib/project.ts | 53 ++-- packages/@aws-cdk/aws-codebuild/package.json | 2 + ...arning-container-build-image.expected.json | 279 ++++++++++++++++++ ...aws-deep-learning-container-build-image.ts | 21 ++ .../test/test.linux-gpu-build-image.ts | 65 ++++ packages/@aws-cdk/aws-ecr/lib/repository.ts | 3 +- .../region-info/build-tools/fact-tables.ts | 28 +- .../build-tools/generate-static-data.ts | 7 +- packages/@aws-cdk/region-info/lib/fact.ts | 6 + .../@aws-cdk/region-info/lib/region-info.ts | 27 ++ 14 files changed, 665 insertions(+), 34 deletions(-) create mode 100644 packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts create mode 100644 packages/@aws-cdk/aws-codebuild/lib/private/run-script-linux-build-spec.ts create mode 100644 packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json create mode 100644 packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.ts create mode 100644 packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index 73b4632722fc4..910a8413645d5 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -238,6 +238,40 @@ The following example shows how to define an image from a private docker registr [Docker Registry example](./test/integ.docker-registry.lit.ts) +### GPU images + +The class `LinuxGpuBuildImage` contains constants for working with +[AWS Deep Learning Container images](https://aws.amazon.com/releasenotes/available-deep-learning-containers-images): + + +```typescript +new codebuild.Project(this, 'Project', { + environment: { + buildImage: codebuild.LinuxGpuBuildImage.DLC_TENSORFLOW_2_1_0_INFERENCE, + }, + ... +}) +``` + +One complication is that the repositories for the DLC images are in +different accounts in different AWS regions. +In most cases, the CDK will handle providing the correct account for you; +in rare cases (for example, deploying to new regions) +where our information might be out of date, +you can always specify the account +(along with the repository name and tag) +explicitly using the `awsDeepLearningContainersImage` method: + +```typescript +new codebuild.Project(this, 'Project', { + environment: { + buildImage: codebuild.LinuxGpuBuildImage.awsDeepLearningContainersImage( + 'tensorflow-inference', '2.1.0-gpu-py36-cu101-ubuntu18.04', '123456789012'), + }, + ... +}) +``` + ## Credentials CodeBuild allows you to store credentials used when communicating with various sources, diff --git a/packages/@aws-cdk/aws-codebuild/lib/index.ts b/packages/@aws-cdk/aws-codebuild/lib/index.ts index 8ecdd6a743476..d1d0907ec734d 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/index.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/index.ts @@ -8,6 +8,7 @@ export * from './artifacts'; export * from './cache'; export * from './build-spec'; export * from './file-location'; +export * from './linux-gpu-build-image'; // AWS::CodeBuild CloudFormation Resources: export * from './codebuild.generated'; diff --git a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts new file mode 100644 index 0000000000000..d9934e546f86d --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts @@ -0,0 +1,141 @@ +import * as ecr from '@aws-cdk/aws-ecr'; +import * as core from '@aws-cdk/core'; +import { FactName, RegionInfo } from '@aws-cdk/region-info'; +import { BuildSpec } from './build-spec'; +import { runScriptLinuxBuildSpec } from './private/run-script-linux-build-spec'; +import { + BuildEnvironment, BuildImageBindOptions, BuildImageConfig, ComputeType, IBindableBuildImage, IBuildImage, + ImagePullPrincipalType, IProject, +} from './project'; + +const mappingName = 'AwsDeepLearningContainersRepositoriesAccounts'; + +/** + * A CodeBuild GPU image running Linux. + * + * This class has public constants that represent the most popular GPU images from AWS Deep Learning Containers. + * + * @see https://aws.amazon.com/releasenotes/available-deep-learning-containers-images + */ +export class LinuxGpuBuildImage implements IBindableBuildImage { + /** Tensorflow 1.14.0 GPU image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_1_14_0 = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-training', + '1.14.0-gpu-py36-cu100-ubuntu16.04'); + /** Tensorflow 1.15.0 GPU image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_1_15_0 = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-training', + '1.15.0-gpu-py36-cu100-ubuntu18.04'); + /** Tensorflow 1.15.2 GPU training image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_1_15_2_TRAINING = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-training', + '1.15.2-gpu-py37-cu100-ubuntu18.04'); + /** Tensorflow 1.15.2 GPU inference image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_1_15_2_INFERENCE = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-inference', + '1.15.2-gpu-py36-cu100-ubuntu18.04'); + /** Tensorflow 2.0.0 GPU image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_2_0_0 = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-training', + '2.0.0-gpu-py36-cu100-ubuntu18.04'); + /** Tensorflow 2.0.1 GPU image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_2_0_1 = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-training', + '2.0.1-gpu-py36-cu100-ubuntu18.04'); + /** Tensorflow 2.1.0 GPU training image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_2_1_0_TRAINING = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-training', + '2.1.0-gpu-py36-cu101-ubuntu18.04'); + /** Tensorflow 2.1.0 GPU inference image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_2_1_0_INFERENCE = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-inference', + '2.1.0-gpu-py36-cu101-ubuntu18.04'); + /** Tensorflow 2.2.0 GPU training image from AWS Deep Learning Containers. */ + public static readonly DLC_TENSORFLOW_2_2_0_TRAINING = LinuxGpuBuildImage.awsDeepLearningContainersImage('tensorflow-training', + '2.2.0-gpu-py37-cu101-ubuntu18.04'); + + /** PyTorch 1.2.0 GPU image from AWS Deep Learning Containers. */ + public static readonly DLC_PYTORCH_1_2_0 = LinuxGpuBuildImage.awsDeepLearningContainersImage('pytorch-training', + '1.2.0-gpu-py36-cu100-ubuntu16.04'); + /** PyTorch 1.3.1 GPU image from AWS Deep Learning Containers. */ + public static readonly DLC_PYTORCH_1_3_1 = LinuxGpuBuildImage.awsDeepLearningContainersImage('pytorch-training', + '1.3.1-gpu-py36-cu101-ubuntu16.04'); + /** PyTorch 1.4.0 GPU training image from AWS Deep Learning Containers. */ + public static readonly DLC_PYTORCH_1_4_0_TRAINING = LinuxGpuBuildImage.awsDeepLearningContainersImage('pytorch-training', + '1.4.0-gpu-py36-cu101-ubuntu16.04'); + /** PyTorch 1.4.0 GPU inference image from AWS Deep Learning Containers. */ + public static readonly DLC_PYTORCH_1_4_0_INFERENCE = LinuxGpuBuildImage.awsDeepLearningContainersImage('pytorch-inference', + '1.4.0-gpu-py36-cu101-ubuntu16.04'); + /** PyTorch 1.5.0 GPU training image from AWS Deep Learning Containers. */ + public static readonly DLC_PYTORCH_1_5_0_TRAINING = LinuxGpuBuildImage.awsDeepLearningContainersImage('pytorch-training', + '1.5.0-gpu-py36-cu101-ubuntu16.04'); + /** PyTorch 1.5.0 GPU inference image from AWS Deep Learning Containers. */ + public static readonly DLC_PYTORCH_1_5_0_INFERENCE = LinuxGpuBuildImage.awsDeepLearningContainersImage('pytorch-inference', + '1.5.0-gpu-py36-cu101-ubuntu16.04'); + + /** MXNet 1.4.1 GPU image from AWS Deep Learning Containers. */ + public static readonly DLC_MXNET_1_4_1 = LinuxGpuBuildImage.awsDeepLearningContainersImage('mxnet-training', + '1.4.1-gpu-py36-cu100-ubuntu16.04'); + /** MXNet 1.6.0 GPU image from AWS Deep Learning Containers. */ + public static readonly DLC_MXNET_1_6_0 = LinuxGpuBuildImage.awsDeepLearningContainersImage('mxnet-training', + '1.6.0-gpu-py36-cu101-ubuntu16.04'); + + /** + * Returns a Linux GPU build image from AWS Deep Learning Containers. + * + * @param repositoryName the name of the repository, + * for example "pytorch-inference" + * @param tag the tag of the image, for example "1.5.0-gpu-py36-cu101-ubuntu16.04" + * @param account the AWS account ID where the DLC repository for this region is hosted in. + * In many cases, the CDK can infer that for you, but for some newer region our information + * might be out of date; in that case, you can specify the region explicitly using this optional parameter + * @see https://aws.amazon.com/releasenotes/available-deep-learning-containers-images + */ + public static awsDeepLearningContainersImage(repositoryName: string, tag: string, account?: string): IBuildImage { + return new LinuxGpuBuildImage(repositoryName, tag, account); + } + + public readonly type = 'LINUX_GPU_CONTAINER'; + public readonly defaultComputeType = ComputeType.LARGE; + public readonly imageId: string; + public readonly imagePullPrincipalType?: ImagePullPrincipalType = ImagePullPrincipalType.SERVICE_ROLE; + + private readonly accountExpression: string; + + private constructor(private readonly repositoryName: string, tag: string, private readonly account: string | undefined) { + this.accountExpression = account ?? core.Fn.findInMap(mappingName, core.Aws.REGION, 'account'); + this.imageId = `${this.accountExpression}.dkr.ecr.${core.Aws.REGION}.${core.Aws.URL_SUFFIX}/${repositoryName}:${tag}`; + } + + public bind(scope: core.Construct, project: IProject, _options: BuildImageBindOptions): BuildImageConfig { + if (!this.account) { + const scopeStack = core.Stack.of(scope); + // Unfortunately, the account IDs of the DLC repositories are not the same in all regions. + // Because of that, use a (singleton) Mapping to find the correct account + if (!scopeStack.node.tryFindChild(mappingName)) { + const mapping: { [k1: string]: { [k2: string]: any } } = {}; + // get the accounts from the region-info module + const region2Accounts = RegionInfo.regionMap(FactName.DLC_REPOSITORY_ACCOUNT); + for (const [region, account] of Object.entries(region2Accounts)) { + mapping[region] = { account }; + } + new core.CfnMapping(scopeStack, mappingName, { mapping }); + } + } + + const repository = ecr.Repository.fromRepositoryAttributes(scope, 'AwsDlcRepositoryCodeBuild', { + repositoryName: this.repositoryName, + repositoryArn: ecr.Repository.arnForLocalRepository(this.repositoryName, scope, this.accountExpression), + }); + repository.grantPull(project); + + return { + }; + } + + public validate(buildEnvironment: BuildEnvironment): string[] { + const ret = []; + if (buildEnvironment.computeType && + buildEnvironment.computeType !== ComputeType.LARGE) { + ret.push(`GPU images only support ComputeType '${ComputeType.LARGE}' - ` + + `'${buildEnvironment.computeType}' was given`); + } + return ret; + } + + public runScriptBuildspec(entrypoint: string): BuildSpec { + return runScriptLinuxBuildSpec(entrypoint); + } +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/private/run-script-linux-build-spec.ts b/packages/@aws-cdk/aws-codebuild/lib/private/run-script-linux-build-spec.ts new file mode 100644 index 0000000000000..6fc63c55cf618 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/lib/private/run-script-linux-build-spec.ts @@ -0,0 +1,32 @@ +import { BuildSpec } from '../build-spec'; + +export const S3_BUCKET_ENV = 'SCRIPT_S3_BUCKET'; +export const S3_KEY_ENV = 'SCRIPT_S3_KEY'; + +export function runScriptLinuxBuildSpec(entrypoint: string) { + return BuildSpec.fromObject({ + version: '0.2', + phases: { + pre_build: { + commands: [ + // Better echo the location here; if this fails, the error message only contains + // the unexpanded variables by default. It might fail if you're running an old + // definition of the CodeBuild project--the permissions will have been changed + // to only allow downloading the very latest version. + `echo "Downloading scripts from s3://\${${S3_BUCKET_ENV}}/\${${S3_KEY_ENV}}"`, + `aws s3 cp s3://\${${S3_BUCKET_ENV}}/\${${S3_KEY_ENV}} /tmp`, + 'mkdir -p /tmp/scriptdir', + `unzip /tmp/$(basename \$${S3_KEY_ENV}) -d /tmp/scriptdir`, + ], + }, + build: { + commands: [ + 'export SCRIPT_DIR=/tmp/scriptdir', + `echo "Running ${entrypoint}"`, + `chmod +x /tmp/scriptdir/${entrypoint}`, + `/tmp/scriptdir/${entrypoint}`, + ], + }, + }, + }); +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index d4f349431b544..153108f7bd24e 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -16,13 +16,11 @@ import { CodePipelineArtifacts } from './codepipeline-artifacts'; import { IFileSystemLocation } from './file-location'; import { NoArtifacts } from './no-artifacts'; import { NoSource } from './no-source'; +import { runScriptLinuxBuildSpec, S3_BUCKET_ENV, S3_KEY_ENV } from './private/run-script-linux-build-spec'; import { renderReportGroupArn } from './report-group-utils'; import { ISource } from './source'; import { CODEPIPELINE_SOURCE_ARTIFACTS_TYPE, NO_SOURCE_TYPE } from './source-types'; -const S3_BUCKET_ENV = 'SCRIPT_S3_BUCKET'; -const S3_KEY_ENV = 'SCRIPT_S3_KEY'; - export interface IProject extends IResource, iam.IGrantable, ec2.IConnectable { /** * The ARN of this Project. @@ -796,6 +794,12 @@ export class Project extends ProjectBase { if (props.encryptionKey) { this.encryptionKey = props.encryptionKey; } + + // bind + const bindFunction = (this.buildImage as any).bind; + if (bindFunction) { + bindFunction.call(this.buildImage, this, this, {}); + } } /** @@ -1196,6 +1200,21 @@ export interface IBuildImage { runScriptBuildspec(entrypoint: string): BuildSpec; } +/** Optional arguments to {@link IBuildImage.binder} - currently empty. */ +export interface BuildImageBindOptions {} + +/** The return type from {@link IBuildImage.binder} - currently empty. */ +export interface BuildImageConfig {} + +// @deprecated(not in tsdoc on purpose): add bind() to IBuildImage +// and get rid of IBindableBuildImage + +/** A variant of {@link IBuildImage} that allows binding to the project. */ +export interface IBindableBuildImage extends IBuildImage { + /** Function that allows the build image access to the construct tree. */ + bind(scope: Construct, project: IProject, options: BuildImageBindOptions): BuildImageConfig; +} + class ArmBuildImage implements IBuildImage { public readonly type = 'ARM_CONTAINER'; public readonly defaultComputeType = ComputeType.LARGE; @@ -1423,34 +1442,6 @@ export class LinuxBuildImage implements IBuildImage { } } -function runScriptLinuxBuildSpec(entrypoint: string) { - return BuildSpec.fromObject({ - version: '0.2', - phases: { - pre_build: { - commands: [ - // Better echo the location here; if this fails, the error message only contains - // the unexpanded variables by default. It might fail if you're running an old - // definition of the CodeBuild project--the permissions will have been changed - // to only allow downloading the very latest version. - `echo "Downloading scripts from s3://\${${S3_BUCKET_ENV}}/\${${S3_KEY_ENV}}"`, - `aws s3 cp s3://\${${S3_BUCKET_ENV}}/\${${S3_KEY_ENV}} /tmp`, - 'mkdir -p /tmp/scriptdir', - `unzip /tmp/$(basename \$${S3_KEY_ENV}) -d /tmp/scriptdir`, - ], - }, - build: { - commands: [ - 'export SCRIPT_DIR=/tmp/scriptdir', - `echo "Running ${entrypoint}"`, - `chmod +x /tmp/scriptdir/${entrypoint}`, - `/tmp/scriptdir/${entrypoint}`, - ], - }, - }, - }); -} - /** * Construction properties of {@link WindowsBuildImage}. * Module-private, as the constructor of {@link WindowsBuildImage} is private. diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index f9e29ceea015a..e218e0644d518 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -91,6 +91,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/region-info": "0.0.0", "constructs": "^3.0.2" }, "homepage": "https://github.com/aws/aws-cdk", @@ -108,6 +109,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/region-info": "0.0.0", "constructs": "^3.0.2" }, "engines": { diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json new file mode 100644 index 0000000000000..d5f641ecb1b9c --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json @@ -0,0 +1,279 @@ +{ + "Resources": { + "ProjectRole4CCB274E": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "ProjectRoleDefaultPolicy7F29461B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "ProjectC78D97AD" + } + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "ProjectC78D97AD" + }, + ":*" + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:CreateReportGroup", + "codebuild:CreateReport", + "codebuild:UpdateReport", + "codebuild:BatchPutTestCases" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":report-group/", + { + "Ref": "ProjectC78D97AD" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Fn::FindInMap": [ + "AwsDeepLearningContainersRepositoriesAccounts", + { + "Ref": "AWS::Region" + }, + "account" + ] + }, + ":repository/mxnet-training" + ] + ] + } + }, + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ProjectRoleDefaultPolicy7F29461B", + "Roles": [ + { + "Ref": "ProjectRole4CCB274E" + } + ] + } + }, + "ProjectC78D97AD": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "NO_ARTIFACTS" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_LARGE", + "Image": { + "Fn::Join": [ + "", + [ + { + "Fn::FindInMap": [ + "AwsDeepLearningContainersRepositoriesAccounts", + { + "Ref": "AWS::Region" + }, + "account" + ] + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/mxnet-training:1.4.1-gpu-py36-cu100-ubuntu16.04" + ] + ] + }, + "ImagePullCredentialsType": "SERVICE_ROLE", + "PrivilegedMode": false, + "Type": "LINUX_GPU_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "ProjectRole4CCB274E", + "Arn" + ] + }, + "Source": { + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"ls\"\n ]\n }\n }\n}", + "Type": "NO_SOURCE" + } + } + } + }, + "Mappings": { + "AwsDeepLearningContainersRepositoriesAccounts": { + "us-east-1": { + "account": "763104351884" + }, + "us-east-2": { + "account": "763104351884" + }, + "us-west-1": { + "account": "763104351884" + }, + "us-west-2": { + "account": "763104351884" + }, + "ca-central-1": { + "account": "763104351884" + }, + "eu-west-1": { + "account": "763104351884" + }, + "eu-west-2": { + "account": "763104351884" + }, + "eu-west-3": { + "account": "763104351884" + }, + "eu-central-1": { + "account": "763104351884" + }, + "eu-north-1": { + "account": "763104351884" + }, + "sa-east-1": { + "account": "763104351884" + }, + "ap-south-1": { + "account": "763104351884" + }, + "ap-northeast-1": { + "account": "763104351884" + }, + "ap-northeast-2": { + "account": "763104351884" + }, + "ap-southeast-1": { + "account": "763104351884" + }, + "ap-southeast-2": { + "account": "763104351884" + }, + "ap-east-1": { + "account": "871362719292" + }, + "me-south-1": { + "account": "217643126080" + }, + "cn-north-1": { + "account": "727897471807" + }, + "cn-northwest-1": { + "account": "727897471807" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.ts b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.ts new file mode 100644 index 0000000000000..13d58db1198b5 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.ts @@ -0,0 +1,21 @@ +import * as core from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +const app = new core.App(); +const stack = new core.Stack(app, 'aws-deep-learning-container-build-image'); + +new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { + commands: ['ls'], + }, + }, + }), + environment: { + buildImage: codebuild.LinuxGpuBuildImage.DLC_MXNET_1_4_1, + }, +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts new file mode 100644 index 0000000000000..b3063b0cf0f01 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts @@ -0,0 +1,65 @@ +import { arrayWith, expect, haveResourceLike, objectLike } from '@aws-cdk/assert'; +import * as cdk from '@aws-cdk/core'; +import { Test } from 'nodeunit'; +import * as codebuild from '../lib'; + +export = { + 'Linux GPU build image': { + 'AWS Deep Learning Container images': { + 'allows passing the account that the repository of the image is hosted in'(test: Test) { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { commands: ['ls'] }, + }, + }), + environment: { + buildImage: codebuild.LinuxGpuBuildImage.awsDeepLearningContainersImage( + 'my-repo', 'my-tag', '123456789012'), + }, + }); + + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + Environment: { + ComputeType: 'BUILD_GENERAL1_LARGE', + Image: { + 'Fn::Join': ['', [ + '123456789012.dkr.ecr.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/my-repo:my-tag', + ]], + }, + }, + })); + + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith(objectLike({ + Action: [ + 'ecr:BatchCheckLayerAvailability', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage', + ], + Resource: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':ecr:', + { Ref: 'AWS::Region' }, + ':123456789012:repository/my-repo', + ]], + }, + })), + }, + })); + + test.done(); + }, + }, + }, +}; diff --git a/packages/@aws-cdk/aws-ecr/lib/repository.ts b/packages/@aws-cdk/aws-ecr/lib/repository.ts index 4d4c0c734443e..0f1aae84354b8 100644 --- a/packages/@aws-cdk/aws-ecr/lib/repository.ts +++ b/packages/@aws-cdk/aws-ecr/lib/repository.ts @@ -394,8 +394,9 @@ export class Repository extends RepositoryBase { * Returns an ECR ARN for a repository that resides in the same account/region * as the current stack. */ - public static arnForLocalRepository(repositoryName: string, scope: IConstruct): string { + public static arnForLocalRepository(repositoryName: string, scope: IConstruct, account?: string): string { return Stack.of(scope).formatArn({ + account, service: 'ecr', resource: 'repository', resourceName: repositoryName, diff --git a/packages/@aws-cdk/region-info/build-tools/fact-tables.ts b/packages/@aws-cdk/region-info/build-tools/fact-tables.ts index b93ca024c9094..4e7ee6eee1261 100644 --- a/packages/@aws-cdk/region-info/build-tools/fact-tables.ts +++ b/packages/@aws-cdk/region-info/build-tools/fact-tables.ts @@ -103,4 +103,30 @@ export const ELBV2_ACCOUNTS: { [region: string]: string } = { 'us-gov-east-1': '190560391635', 'cn-north-1': '638102146993', 'cn-northwest-1': '037604701340', -}; \ No newline at end of file +}; + +// https://aws.amazon.com/releasenotes/available-deep-learning-containers-images +export const DLC_REPOSITORY_ACCOUNTS: { [region: string]: string } = { + 'us-east-1': '763104351884', + 'us-east-2': '763104351884', + 'us-west-1': '763104351884', + 'us-west-2': '763104351884', + 'ca-central-1': '763104351884', + 'eu-west-1': '763104351884', + 'eu-west-2': '763104351884', + 'eu-west-3': '763104351884', + 'eu-central-1': '763104351884', + 'eu-north-1': '763104351884', + 'sa-east-1': '763104351884', + 'ap-south-1': '763104351884', + 'ap-northeast-1': '763104351884', + 'ap-northeast-2': '763104351884', + 'ap-southeast-1': '763104351884', + 'ap-southeast-2': '763104351884', + + 'ap-east-1': '871362719292', + 'me-south-1': '217643126080', + + 'cn-north-1': '727897471807', + 'cn-northwest-1': '727897471807', +}; diff --git a/packages/@aws-cdk/region-info/build-tools/generate-static-data.ts b/packages/@aws-cdk/region-info/build-tools/generate-static-data.ts index abcc335b308d0..bc042279d8e50 100644 --- a/packages/@aws-cdk/region-info/build-tools/generate-static-data.ts +++ b/packages/@aws-cdk/region-info/build-tools/generate-static-data.ts @@ -2,7 +2,10 @@ import * as path from 'path'; import * as fs from 'fs-extra'; import { Default } from '../lib/default'; import { AWS_REGIONS, AWS_SERVICES } from './aws-entities'; -import { AWS_CDK_METADATA, AWS_OLDER_REGIONS, ELBV2_ACCOUNTS, PARTITION_MAP, ROUTE_53_BUCKET_WEBSITE_ZONE_IDS } from './fact-tables'; +import { + AWS_CDK_METADATA, AWS_OLDER_REGIONS, DLC_REPOSITORY_ACCOUNTS, ELBV2_ACCOUNTS, PARTITION_MAP, + ROUTE_53_BUCKET_WEBSITE_ZONE_IDS, +} from './fact-tables'; async function main(): Promise { const lines = [ @@ -49,6 +52,8 @@ async function main(): Promise { registerFact(region, 'ELBV2_ACCOUNT', ELBV2_ACCOUNTS[region]); + registerFact(region, 'DLC_REPOSITORY_ACCOUNT', DLC_REPOSITORY_ACCOUNTS[region]); + const vpcEndpointServiceNamePrefix = `${domainSuffix.split('.').reverse().join('.')}.vpce`; registerFact(region, 'VPC_ENDPOINT_SERVICE_NAME_PREFIX', vpcEndpointServiceNamePrefix); diff --git a/packages/@aws-cdk/region-info/lib/fact.ts b/packages/@aws-cdk/region-info/lib/fact.ts index 3936f9c129449..79033f9c9adb9 100644 --- a/packages/@aws-cdk/region-info/lib/fact.ts +++ b/packages/@aws-cdk/region-info/lib/fact.ts @@ -140,6 +140,12 @@ export class FactName { */ public static readonly ELBV2_ACCOUNT = 'elbv2Account'; + /** + * The ID of the AWS account that owns the public ECR repository that contains the + * AWS Deep Learning Containers images in a given region. + */ + public static readonly DLC_REPOSITORY_ACCOUNT = 'dlcRepositoryAccount'; + /** * The name of the regional service principal for a given service. * diff --git a/packages/@aws-cdk/region-info/lib/region-info.ts b/packages/@aws-cdk/region-info/lib/region-info.ts index cc424bf304bf1..3402cb8fd657f 100644 --- a/packages/@aws-cdk/region-info/lib/region-info.ts +++ b/packages/@aws-cdk/region-info/lib/region-info.ts @@ -12,6 +12,25 @@ export class RegionInfo { return Fact.regions.map(RegionInfo.get); } + /** + * Retrieves a collection of all fact values for all regions that fact is defined in. + * + * @param factName the name of the fact to retrieve values for. + * For a list of common fact names, see the FactName class + * @returns a mapping with AWS region codes as the keys, + * and the fact in the given region as the value for that key + */ + public static regionMap(factName: string): { [region: string]: string } { + const ret: { [region: string]: string } = {}; + for (const regionInfo of RegionInfo.regions) { + const fact = Fact.find(regionInfo.name, factName); + if (fact) { + ret[regionInfo.name] = fact; + } + } + return ret; + } + /** * Obtain region info for a given region name. * @@ -82,4 +101,12 @@ export class RegionInfo { public get elbv2Account(): string | undefined { return Fact.find(this.name, FactName.ELBV2_ACCOUNT); } + + /** + * The ID of the AWS account that owns the public ECR repository containing the + * AWS Deep Learning Containers images in this region. + */ + public get dlcRepositoryAccount(): string | undefined { + return Fact.find(this.name, FactName.DLC_REPOSITORY_ACCOUNT); + } } From 16bb36a85f43e4fc930202df65d7dd04f7186f46 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2020 18:57:21 +0000 Subject: [PATCH 41/43] chore(deps-dev): bump @types/uuid from 8.0.0 to 8.3.0 (#9649) Bumps [@types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/uuid) from 8.0.0 to 8.3.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/uuid) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/aws-cdk/package.json | 2 +- yarn.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index f1bc8e6cda1d8..ea51c1177340a 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -52,7 +52,7 @@ "@types/semver": "^7.3.1", "@types/sinon": "^9.0.4", "@types/table": "^4.0.7", - "@types/uuid": "^8.0.0", + "@types/uuid": "^8.3.0", "@types/wrap-ansi": "^3.0.0", "@types/yaml": "^1.9.7", "@types/yargs": "^15.0.5", diff --git a/yarn.lock b/yarn.lock index ed5cf3f1e9b63..2b366de4263f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1618,10 +1618,10 @@ resolved "https://registry.yarnpkg.com/@types/table/-/table-4.0.7.tgz#c21100d37d4924abbbde85414170260d4d7b0316" integrity sha512-HKtXvBxU8U8evZCSlUi9HbfT/SFW7nSGCoiBEheB06jAhXeW6JbGh8biEAqIFG5rZo9f8xeJVdIn455sddmIcw== -"@types/uuid@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.0.tgz#165aae4819ad2174a17476dbe66feebd549556c0" - integrity sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw== +"@types/uuid@^8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== "@types/wrap-ansi@^3.0.0": version "3.0.0" @@ -9077,9 +9077,9 @@ tap-mocha-reporter@^3.0.9, tap-mocha-reporter@^5.0.1: unicode-length "^2.0.2" tap-parser@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-10.0.1.tgz#b63c2500eeef2be8fbf09d512914196d1f12ebec" - integrity sha512-qdT15H0DoJIi7zOqVXDn9X0gSM68JjNy1w3VemwTJlDnETjbi6SutnqmBfjDJAwkFS79NJ97gZKqie00ZCGmzg== + version "10.1.0" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-10.1.0.tgz#7b1aac40dbcaa4716c0b58952686eae65d2b74ad" + integrity sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA== dependencies: events-to-array "^1.0.1" minipass "^3.0.0" From 4c62702fe886a41e00a0be1fdf12bdb75a9ac968 Mon Sep 17 00:00:00 2001 From: Nick Lynch Date: Wed, 12 Aug 2020 20:19:35 +0100 Subject: [PATCH 42/43] feat(cloudfront): Distribution support for logging, geo restrictions, http version and IPv6 (#9635) Adding support for most of the missing attributes for `DistributionProps`, including HttpVersion, Logging, Geo restrictions, and WAF ACLs. The only missing property now is "aliases", which needs some design work alongside the certificate usage. I also added two integ tests for `Distribution`, as previously all integ tests were only in the `aws-cloudfront-origins` module. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../test/integ.http-origin.expected.json | 2 + .../integ.load-balancer-origin.expected.json | 2 + .../test/integ.origin-group.expected.json | 2 + .../test/integ.s3-origin.expected.json | 2 + packages/@aws-cdk/aws-cloudfront/README.md | 22 +++ .../aws-cloudfront/lib/distribution.ts | 134 ++++++++++++++- .../aws-cloudfront/lib/geo-restriction.ts | 52 ++++++ packages/@aws-cdk/aws-cloudfront/lib/index.ts | 3 +- .../aws-cloudfront/lib/web_distribution.ts | 61 +------ packages/@aws-cdk/aws-cloudfront/package.json | 3 - .../aws-cloudfront/test/distribution.test.ts | 162 ++++++++++++++++-- .../test/geo-restriction.test.ts | 27 +++ .../integ.distribution-basic.expected.json | 30 ++++ .../test/integ.distribution-basic.ts | 12 ++ ...integ.distribution-extensive.expected.json | 57 ++++++ .../test/integ.distribution-extensive.ts | 22 +++ .../aws-cloudfront/test/origin.test.ts | 10 +- .../aws-cloudfront/test/test-origin.ts | 13 ++ 18 files changed, 530 insertions(+), 86 deletions(-) create mode 100644 packages/@aws-cdk/aws-cloudfront/lib/geo-restriction.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.distribution-basic.expected.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.distribution-basic.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json create mode 100644 packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.ts create mode 100644 packages/@aws-cdk/aws-cloudfront/test/test-origin.ts diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.http-origin.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.http-origin.expected.json index 34b8f67a5b66f..a4f80dc55a8e0 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.http-origin.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.http-origin.expected.json @@ -12,6 +12,8 @@ "ViewerProtocolPolicy": "allow-all" }, "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, "Origins": [ { "CustomOriginConfig": { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.load-balancer-origin.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.load-balancer-origin.expected.json index 1b83e071d6275..d01791d8e6cb4 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.load-balancer-origin.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.load-balancer-origin.expected.json @@ -412,6 +412,8 @@ "ViewerProtocolPolicy": "allow-all" }, "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, "Origins": [ { "CustomOriginConfig": { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json index 21d939154cff2..b3d92abe8d269 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.origin-group.expected.json @@ -76,6 +76,8 @@ "ViewerProtocolPolicy": "allow-all" }, "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, "OriginGroups": { "Items": [ { diff --git a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json index 919d482d8b880..0a1d437718590 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/test/integ.s3-origin.expected.json @@ -76,6 +76,8 @@ "ViewerProtocolPolicy": "allow-all" }, "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, "Origins": [ { "DomainName": { diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index f71cf9f971391..c13af4ace9e05 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -221,6 +221,28 @@ myDistribution.addBehavior('images/*', myOrigin, { }); ``` +### Logging + +You can configure CloudFront to create log files that contain detailed information about every user request that CloudFront receives. +The logs can go to either an existing bucket, or a bucket will be created for you. + +```ts +// Simplest form - creates a new bucket and logs to it. +new cloudfront.Distribution(this, 'myDist', { + defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, + enableLogging: true, +}); + +// You can optionally log to a specific bucket, configure whether cookies are logged, and give the log files a prefix. +new cloudfront.Distribution(this, 'myDist', { + defaultBehavior: { origin: new origins.HttpOrigin('www.example.com') }, + enableLogging: true, // Optional, this is implied if loggingBucket is specified + loggingBucket: new s3.Bucket(this, 'LoggingBucket'), + loggingFilePrefix: 'distribution-access-logs/', + loggingIncludesCookies: true, +}); +``` + ## CloudFrontWebDistribution API - Stable ![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index 48300b3faae83..dee47eaa122df 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -1,7 +1,9 @@ import * as acm from '@aws-cdk/aws-certificatemanager'; import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; import { Construct, IResource, Lazy, Resource, Stack, Token, Duration } from '@aws-cdk/core'; import { CfnDistribution } from './cloudfront.generated'; +import { GeoRestriction } from './geo-restriction'; import { IOrigin, OriginBindConfig, OriginBindOptions } from './origin'; import { CacheBehavior } from './private/cache-behavior'; @@ -82,6 +84,83 @@ export interface DistributionProps { */ readonly certificate?: acm.ICertificate; + /** + * Any comments you want to include about the distribution. + * + * @default - no comment + */ + readonly comment?: string; + + /** + * The object that you want CloudFront to request from your origin (for example, index.html) + * when a viewer requests the root URL for your distribution. If no default object is set, the + * request goes to the origin's root (e.g., example.com/). + * + * @default - no default root object + */ + readonly defaultRootObject?: string; + + /** + * Enable or disable the distribution. + * + * @default true + */ + readonly enabled?: boolean; + + /** + * Whether CloudFront will respond to IPv6 DNS requests with an IPv6 address. + * + * If you specify false, CloudFront responds to IPv6 DNS requests with the DNS response code NOERROR and with no IP addresses. + * This allows viewers to submit a second request, for an IPv4 address for your distribution. + * + * @default true + */ + readonly enableIpv6?: boolean; + + /** + * Enable access logging for the distribution. + * + * @default - false, unless `loggingBucket` is specified. + */ + readonly enableLogging?: boolean; + + /** + * Controls the countries in which your content is distributed. + * + * @default - No geographic restrictions + */ + readonly geoRestriction?: GeoRestriction; + + /** + * Specify the maximum HTTP version that you want viewers to use to communicate with CloudFront. + * + * For viewers and CloudFront to use HTTP/2, viewers must support TLS 1.2 or later, and must support server name identification (SNI). + * + * @default HttpVersion.HTTP2 + */ + readonly httpVersion?: HttpVersion; + + /** + * The Amazon S3 bucket to store the access logs in. + * + * @default - A bucket is created if `enableLogging` is true + */ + readonly logBucket?: s3.IBucket; + + /** + * Specifies whether you want CloudFront to include cookies in access logs + * + * @default false + */ + readonly logIncludesCookies?: boolean; + + /** + * An optional string that you want CloudFront to prefix to the access log filenames for this distribution. + * + * @default - no prefix + */ + readonly logFilePrefix?: string; + /** * The price class that corresponds with the maximum price that you want to pay for CloudFront service. * If you specify PriceClass_All, CloudFront responds to requests for your objects from all CloudFront edge locations. @@ -92,6 +171,20 @@ export interface DistributionProps { */ readonly priceClass?: PriceClass; + /** + * Unique identifier that specifies the AWS WAF web ACL to associate with this CloudFront distribution. + * + * To specify a web ACL created using the latest version of AWS WAF, use the ACL ARN, for example + * `arn:aws:wafv2:us-east-1:123456789012:global/webacl/ExampleWebACL/473e64fd-f30b-4765-81a0-62ad96dd167a`. + * To specify a web ACL created using AWS WAF Classic, use the ACL ID, for example `473e64fd-f30b-4765-81a0-62ad96dd167a`. + * + * @see https://docs.aws.amazon.com/waf/latest/developerguide/what-is-aws-waf.html + * @see https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html#API_CreateDistribution_RequestParameters. + * + * @default - No AWS Web Application Firewall web access control list (web ACL). + */ + readonly webAclId?: string; + /** * How CloudFront should handle requests that are not successful (e.g., PageNotFound). * @@ -159,14 +252,20 @@ export class Distribution extends Resource implements IDistribution { this.errorResponses = props.errorResponses ?? []; const distribution = new CfnDistribution(this, 'Resource', { distributionConfig: { - enabled: true, + enabled: props.enabled ?? true, origins: Lazy.anyValue({ produce: () => this.renderOrigins() }), originGroups: Lazy.anyValue({ produce: () => this.renderOriginGroups() }), defaultCacheBehavior: this.defaultBehavior._renderBehavior(), cacheBehaviors: Lazy.anyValue({ produce: () => this.renderCacheBehaviors() }), - viewerCertificate: this.certificate ? this.renderViewerCertificate(this.certificate) : undefined, + comment: props.comment, customErrorResponses: this.renderErrorResponses(), + defaultRootObject: props.defaultRootObject, + httpVersion: props.httpVersion ?? HttpVersion.HTTP2, + ipv6Enabled: props.enableIpv6 ?? true, + logging: this.renderLogging(props), priceClass: props.priceClass ?? undefined, + restrictions: this.renderRestrictions(props.geoRestriction), + viewerCertificate: this.certificate ? this.renderViewerCertificate(this.certificate) : undefined, } }); this.domainName = distribution.attrDomainName; @@ -280,6 +379,29 @@ export class Distribution extends Resource implements IDistribution { }); } + private renderLogging(props: DistributionProps): CfnDistribution.LoggingProperty | undefined { + if (!props.enableLogging && !props.logBucket) { return undefined; } + if (props.enableLogging === false && props.logBucket) { + throw new Error('Explicitly disabled logging but provided a logging bucket.'); + } + + const bucket = props.logBucket ?? new s3.Bucket(this, 'LoggingBucket'); + return { + bucket: bucket.bucketRegionalDomainName, + includeCookies: props.logIncludesCookies, + prefix: props.logFilePrefix, + }; + } + + private renderRestrictions(geoRestriction?: GeoRestriction) { + return geoRestriction ? { + geoRestriction: { + restrictionType: geoRestriction.restrictionType, + locations: geoRestriction.locations, + }, + } : undefined; + } + private renderViewerCertificate(certificate: acm.ICertificate): CfnDistribution.ViewerCertificateProperty { return { acmCertificateArn: certificate.certificateArn, @@ -289,6 +411,14 @@ export class Distribution extends Resource implements IDistribution { } } +/** Maximum HTTP version to support */ +export enum HttpVersion { + /** HTTP 1.1 */ + HTTP1_1 = 'http1.1', + /** HTTP 2 */ + HTTP2 = 'http2' +} + /** * The price class determines how many edge locations CloudFront will use for your distribution. * See https://aws.amazon.com/cloudfront/pricing/ for full list of supported regions. diff --git a/packages/@aws-cdk/aws-cloudfront/lib/geo-restriction.ts b/packages/@aws-cdk/aws-cloudfront/lib/geo-restriction.ts new file mode 100644 index 0000000000000..7c18b2f7ebc68 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/lib/geo-restriction.ts @@ -0,0 +1,52 @@ +/** + * Controls the countries in which content is distributed. + */ +export class GeoRestriction { + + /** + * Whitelist specific countries which you want CloudFront to distribute your content. + * + * @param locations Two-letter, uppercase country code for a country + * that you want to whitelist. Include one element for each country. + * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website + */ + public static whitelist(...locations: string[]) { + return new GeoRestriction('whitelist', GeoRestriction.validateLocations(locations)); + } + + /** + * Blacklist specific countries which you don't want CloudFront to distribute your content. + * + * @param locations Two-letter, uppercase country code for a country + * that you want to blacklist. Include one element for each country. + * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website + */ + public static blacklist(...locations: string[]) { + return new GeoRestriction('blacklist', GeoRestriction.validateLocations(locations)); + } + + private static LOCATION_REGEX = /^[A-Z]{2}$/; + + private static validateLocations(locations: string[]) { + if (locations.length === 0) { + throw new Error('Should provide at least 1 location'); + } + locations.forEach(location => { + if (!GeoRestriction.LOCATION_REGEX.test(location)) { + // eslint-disable-next-line max-len + throw new Error(`Invalid location format for location: ${location}, location should be two-letter and uppercase country ISO 3166-1-alpha-2 code`); + } + }); + return locations; + } + + /** + * Creates an instance of GeoRestriction for internal use + * + * @param restrictionType Specifies the restriction type to impose (whitelist or blacklist) + * @param locations Two-letter, uppercase country code for a country + * that you want to whitelist/blacklist. Include one element for each country. + * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website + */ + private constructor(readonly restrictionType: 'whitelist' | 'blacklist', readonly locations: string[]) {} +} diff --git a/packages/@aws-cdk/aws-cloudfront/lib/index.ts b/packages/@aws-cdk/aws-cloudfront/lib/index.ts index bf106211657c9..cf78bf5cdd7e0 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/index.ts @@ -1,7 +1,8 @@ export * from './distribution'; -export * from './web_distribution'; +export * from './geo-restriction'; export * from './origin'; export * from './origin_access_identity'; +export * from './web_distribution'; // AWS::CloudFront CloudFormation Resources: export * from './cloudfront.generated'; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index b2fc472adfd46..c2d8343cdbe10 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -4,14 +4,10 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { CfnDistribution } from './cloudfront.generated'; -import { IDistribution, LambdaEdgeEventType, OriginProtocolPolicy, PriceClass, ViewerProtocolPolicy, SSLMethod, SecurityPolicyProtocol } from './distribution'; +import { HttpVersion, IDistribution, LambdaEdgeEventType, OriginProtocolPolicy, PriceClass, ViewerProtocolPolicy, SSLMethod, SecurityPolicyProtocol } from './distribution'; +import { GeoRestriction } from './geo-restriction'; import { IOriginAccessIdentity } from './origin_access_identity'; -export enum HttpVersion { - HTTP1_1 = 'http1.1', - HTTP2 = 'http2' -} - /** * HTTP status code to failover to second origin */ @@ -515,59 +511,6 @@ export class ViewerCertificate { public readonly aliases: string[] = []) { } } -/** - * Controls the countries in which your content is distributed. - */ -export class GeoRestriction { - - /** - * Whitelist specific countries which you want CloudFront to distribute your content. - * - * @param locations Two-letter, uppercase country code for a country - * that you want to whitelist. Include one element for each country. - * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website - */ - public static whitelist(...locations: string[]) { - return new GeoRestriction('whitelist', GeoRestriction.validateLocations(locations)); - } - - /** - * Blacklist specific countries which you don't want CloudFront to distribute your content. - * - * @param locations Two-letter, uppercase country code for a country - * that you want to blacklist. Include one element for each country. - * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website - */ - public static blacklist(...locations: string[]) { - return new GeoRestriction('blacklist', GeoRestriction.validateLocations(locations)); - } - - private static LOCATION_REGEX = /^[A-Z]{2}$/; - - private static validateLocations(locations: string[]) { - if (locations.length === 0) { - throw new Error('Should provide at least 1 location'); - } - locations.forEach(location => { - if (!GeoRestriction.LOCATION_REGEX.test(location)) { - // eslint-disable-next-line max-len - throw new Error(`Invalid location format for location: ${location}, location should be two-letter and uppercase country ISO 3166-1-alpha-2 code`); - } - }); - return locations; - } - - /** - * Creates an instance of GeoRestriction for internal use - * - * @param restrictionType Specifies the restriction type to impose (whitelist or blacklist) - * @param locations Two-letter, uppercase country code for a country - * that you want to whitelist/blacklist. Include one element for each country. - * See ISO 3166-1-alpha-2 code on the *International Organization for Standardization* website - */ - private constructor(readonly restrictionType: 'whitelist' | 'blacklist', readonly locations: string[]) {} -} - export interface CloudFrontWebDistributionProps { /** diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 45b22ae133343..ad24a82a2d4b3 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -126,9 +126,6 @@ "docs-public-apis:@aws-cdk/aws-cloudfront.CloudFrontAllowedMethods.GET_HEAD", "docs-public-apis:@aws-cdk/aws-cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS", "docs-public-apis:@aws-cdk/aws-cloudfront.CloudFrontAllowedMethods.ALL", - "docs-public-apis:@aws-cdk/aws-cloudfront.HttpVersion", - "docs-public-apis:@aws-cdk/aws-cloudfront.HttpVersion.HTTP1_1", - "docs-public-apis:@aws-cdk/aws-cloudfront.HttpVersion.HTTP2", "docs-public-apis:@aws-cdk/aws-cloudfront.OriginSslPolicy", "docs-public-apis:@aws-cdk/aws-cloudfront.OriginSslPolicy.SSL_V3", "docs-public-apis:@aws-cdk/aws-cloudfront.OriginSslPolicy.TLS_V1", diff --git a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts index 60275f1cf07d0..34e0177777ed7 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts @@ -1,8 +1,11 @@ +import { ABSENT } from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import * as acm from '@aws-cdk/aws-certificatemanager'; import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, Stack } from '@aws-cdk/core'; -import { CfnDistribution, Distribution, IOrigin, LambdaEdgeEventType, OriginBase, OriginProps, OriginProtocolPolicy, PriceClass } from '../lib'; +import { CfnDistribution, Distribution, GeoRestriction, HttpVersion, IOrigin, LambdaEdgeEventType, PriceClass } from '../lib'; +import { defaultOrigin } from './test-origin'; let app: App; let stack: Stack; @@ -26,6 +29,8 @@ test('minimal example renders correctly', () => { ViewerProtocolPolicy: 'allow-all', }, Enabled: true, + HttpVersion: 'http2', + IPV6Enabled: true, Origins: [{ DomainName: 'www.example.com', Id: 'StackMyDistOrigin1D6D5E535', @@ -37,6 +42,66 @@ test('minimal example renders correctly', () => { }); }); +test('exhaustive example of props renders correctly', () => { + const origin = defaultOrigin(); + const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012'); + + new Distribution(stack, 'MyDist', { + defaultBehavior: { origin }, + certificate, + comment: 'a test', + defaultRootObject: 'index.html', + enabled: false, + enableIpv6: false, + enableLogging: true, + geoRestriction: GeoRestriction.blacklist('US', 'GB'), + httpVersion: HttpVersion.HTTP1_1, + logFilePrefix: 'logs/', + logIncludesCookies: true, + priceClass: PriceClass.PRICE_CLASS_100, + webAclId: '473e64fd-f30b-4765-81a0-62ad96dd167a', + }); + + expect(stack).toHaveResource('AWS::CloudFront::Distribution', { + DistributionConfig: { + DefaultCacheBehavior: { + ForwardedValues: { QueryString: false }, + TargetOriginId: 'StackMyDistOrigin1D6D5E535', + ViewerProtocolPolicy: 'allow-all', + }, + Comment: 'a test', + DefaultRootObject: 'index.html', + Enabled: false, + HttpVersion: 'http1.1', + IPV6Enabled: false, + Logging: { + Bucket: {'Fn::GetAtt': ['MyDistLoggingBucket9B8976BC', 'RegionalDomainName']}, + IncludeCookies: true, + Prefix: 'logs/', + }, + Origins: [{ + DomainName: 'www.example.com', + Id: 'StackMyDistOrigin1D6D5E535', + CustomOriginConfig: { + OriginProtocolPolicy: 'https-only', + }, + }], + PriceClass: 'PriceClass_100', + Restrictions: { + GeoRestriction: { + Locations: ['US', 'GB'], + RestrictionType: 'blacklist', + }, + }, + ViewerCertificate: { + AcmCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012', + SslSupportMethod: 'sni-only', + MinimumProtocolVersion: 'TLSv1.2_2018', + }, + }, + }); +}); + describe('multiple behaviors', () => { test('a second behavior can\'t be specified with the catch-all path pattern', () => { @@ -75,6 +140,8 @@ describe('multiple behaviors', () => { ViewerProtocolPolicy: 'allow-all', }], Enabled: true, + HttpVersion: 'http2', + IPV6Enabled: true, Origins: [{ DomainName: 'www.example.com', Id: 'StackMyDistOrigin1D6D5E535', @@ -110,6 +177,8 @@ describe('multiple behaviors', () => { ViewerProtocolPolicy: 'allow-all', }], Enabled: true, + HttpVersion: 'http2', + IPV6Enabled: true, Origins: [{ DomainName: 'www.example.com', Id: 'StackMyDistOrigin1D6D5E535', @@ -159,6 +228,8 @@ describe('multiple behaviors', () => { ViewerProtocolPolicy: 'allow-all', }], Enabled: true, + HttpVersion: 'http2', + IPV6Enabled: true, Origins: [{ DomainName: 'www.example.com', Id: 'StackMyDistOrigin1D6D5E535', @@ -273,6 +344,84 @@ describe('custom error responses', () => { }); +describe('logging', () => { + test('does not include logging if disabled and no bucket provided', () => { + const origin = defaultOrigin(); + new Distribution(stack, 'MyDist', { defaultBehavior: { origin } }); + + expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + DistributionConfig: { + Logging: ABSENT, + }, + }); + }); + + test('throws error if logging disabled but bucket provided', () => { + const origin = defaultOrigin(); + + expect(() => { + new Distribution(stack, 'MyDist', { + defaultBehavior: { origin }, + enableLogging: false, + logBucket: new s3.Bucket(stack, 'Bucket'), + }); + }).toThrow(/Explicitly disabled logging but provided a logging bucket./); + }); + + test('creates bucket if none is provided', () => { + const origin = defaultOrigin(); + new Distribution(stack, 'MyDist', { + defaultBehavior: { origin }, + enableLogging: true, + }); + + expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + DistributionConfig: { + Logging: { + Bucket: {'Fn::GetAtt': ['MyDistLoggingBucket9B8976BC', 'RegionalDomainName']}, + }, + }, + }); + }); + + test('uses existing bucket if provided', () => { + const origin = defaultOrigin(); + const loggingBucket = new s3.Bucket(stack, 'MyLoggingBucket'); + new Distribution(stack, 'MyDist', { + defaultBehavior: { origin }, + logBucket: loggingBucket, + }); + + expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + DistributionConfig: { + Logging: { + Bucket: {'Fn::GetAtt': ['MyLoggingBucket4382CD04', 'RegionalDomainName']}, + }, + }, + }); + }); + + test('can set prefix and cookies', () => { + const origin = defaultOrigin(); + new Distribution(stack, 'MyDist', { + defaultBehavior: { origin }, + enableLogging: true, + logFilePrefix: 'logs/', + logIncludesCookies: true, + }); + + expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { + DistributionConfig: { + Logging: { + Bucket: {'Fn::GetAtt': ['MyDistLoggingBucket9B8976BC', 'RegionalDomainName']}, + IncludeCookies: true, + Prefix: 'logs/', + }, + }, + }); + }); +}); + describe('with Lambda@Edge functions', () => { let lambdaFunction: lambda.Function; let origin: IOrigin; @@ -399,14 +548,3 @@ test('escape hatches are supported', () => { }, }); }); - -function defaultOrigin(domainName?: string): IOrigin { - return new TestOrigin(domainName ?? 'www.example.com'); -} - -class TestOrigin extends OriginBase { - constructor(domainName: string, props: OriginProps = {}) { super(domainName, props); } - protected renderCustomOriginConfig(): CfnDistribution.CustomOriginConfigProperty | undefined { - return { originProtocolPolicy: OriginProtocolPolicy.HTTPS_ONLY }; - } -} diff --git a/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts b/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts new file mode 100644 index 0000000000000..23af143c67851 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/geo-restriction.test.ts @@ -0,0 +1,27 @@ +import '@aws-cdk/assert/jest'; +import { GeoRestriction } from '../lib'; + +describe.each([ + ['whitelist', GeoRestriction.whitelist], + ['blacklist', GeoRestriction.blacklist], +])('%s', (type, geoFn) => { + + test('throws is location is empty', () => { + expect(() => { geoFn(); }).toThrow(/Should provide at least 1 location/); + }); + + test('throws if locations are the wrong format', () => { + const error = /Invalid location format for location: .*/; + expect(() => { geoFn('a'); }).toThrow(error); + expect(() => { geoFn('abc'); }).toThrow(error); + expect(() => { geoFn('ab'); }).toThrow(error); + expect(() => { geoFn('a1'); }).toThrow(error); + }); + + test('includes proper restriction type and location list', () => { + const restriction = geoFn('US', 'GB'); + expect(restriction.restrictionType).toEqual(type); + expect(restriction.locations).toEqual(['US', 'GB']); + }); + +}); diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-basic.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-basic.expected.json new file mode 100644 index 0000000000000..26a9b80a80b67 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-basic.expected.json @@ -0,0 +1,30 @@ +{ + "Resources": { + "DistB3B78991": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "DefaultCacheBehavior": { + "ForwardedValues": { + "QueryString": false + }, + "TargetOriginId": "integdistributionbasicDistOrigin151B53FF1", + "ViewerProtocolPolicy": "allow-all" + }, + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "CustomOriginConfig": { + "OriginProtocolPolicy": "https-only" + }, + "DomainName": "www.example.com", + "Id": "integdistributionbasicDistOrigin151B53FF1" + } + ] + } + } + } + } +} diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-basic.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-basic.ts new file mode 100644 index 0000000000000..61fd0f0872077 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-basic.ts @@ -0,0 +1,12 @@ +import * as cdk from '@aws-cdk/core'; +import * as cloudfront from '../lib'; +import { TestOrigin } from './test-origin'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integ-distribution-basic'); + +new cloudfront.Distribution(stack, 'Dist', { + defaultBehavior: { origin: new TestOrigin('www.example.com') }, +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json new file mode 100644 index 0000000000000..587b65b5f98f9 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.expected.json @@ -0,0 +1,57 @@ +{ + "Resources": { + "MyDistLoggingBucket9B8976BC": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "MyDistDB88FD9A": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "Comment": "a test", + "DefaultCacheBehavior": { + "ForwardedValues": { + "QueryString": false + }, + "TargetOriginId": "integdistributionextensiveMyDistOrigin185F089B3", + "ViewerProtocolPolicy": "allow-all" + }, + "DefaultRootObject": "index.html", + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Logging": { + "Bucket": { + "Fn::GetAtt": [ + "MyDistLoggingBucket9B8976BC", + "RegionalDomainName" + ] + }, + "IncludeCookies": true, + "Prefix": "logs/" + }, + "Origins": [ + { + "CustomOriginConfig": { + "OriginProtocolPolicy": "https-only" + }, + "DomainName": "www.example.com", + "Id": "integdistributionextensiveMyDistOrigin185F089B3" + } + ], + "PriceClass": "PriceClass_100", + "Restrictions": { + "GeoRestriction": { + "Locations": [ + "US", + "GB" + ], + "RestrictionType": "whitelist" + } + } + } + } + } + } +} diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.ts new file mode 100644 index 0000000000000..6a8f949ca9b43 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-extensive.ts @@ -0,0 +1,22 @@ +import * as cdk from '@aws-cdk/core'; +import * as cloudfront from '../lib'; +import { TestOrigin } from './test-origin'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integ-distribution-extensive'); + +new cloudfront.Distribution(stack, 'MyDist', { + defaultBehavior: { origin: new TestOrigin('www.example.com') }, + comment: 'a test', + defaultRootObject: 'index.html', + enabled: true, + enableIpv6: true, + enableLogging: true, + geoRestriction: cloudfront.GeoRestriction.whitelist('US', 'GB'), + httpVersion: cloudfront.HttpVersion.HTTP2, + logFilePrefix: 'logs/', + logIncludesCookies: true, + priceClass: cloudfront.PriceClass.PRICE_CLASS_100, +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts index a9d553dbe01c0..cbf3b32ad6f10 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/origin.test.ts @@ -1,6 +1,6 @@ import '@aws-cdk/assert/jest'; import { App, Stack, Duration } from '@aws-cdk/core'; -import { CfnDistribution, OriginProtocolPolicy, OriginBase, OriginProps } from '../lib'; +import { TestOrigin } from './test-origin'; let app: App; let stack: Stack; @@ -44,11 +44,3 @@ test.each(['api', '/api', '/api/', 'api/']) expect(originBindConfig.originProperty?.originPath).toEqual('/api'); }); - -/** Used for testing common Origin functionality */ -class TestOrigin extends OriginBase { - constructor(domainName: string, props: OriginProps = {}) { super(domainName, props); } - protected renderCustomOriginConfig(): CfnDistribution.CustomOriginConfigProperty | undefined { - return { originProtocolPolicy: OriginProtocolPolicy.HTTPS_ONLY }; - } -} diff --git a/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts b/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts new file mode 100644 index 0000000000000..c39c632389e1b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts @@ -0,0 +1,13 @@ +import { CfnDistribution, IOrigin, OriginBase, OriginProps, OriginProtocolPolicy } from '../lib'; + +/** Used for testing common Origin functionality */ +export class TestOrigin extends OriginBase { + constructor(domainName: string, props: OriginProps = {}) { super(domainName, props); } + protected renderCustomOriginConfig(): CfnDistribution.CustomOriginConfigProperty | undefined { + return { originProtocolPolicy: OriginProtocolPolicy.HTTPS_ONLY }; + } +} + +export function defaultOrigin(domainName?: string): IOrigin { + return new TestOrigin(domainName ?? 'www.example.com'); +} From 0ea4ea3734c4fb136515d85f9b0a791649aa51f2 Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Wed, 12 Aug 2020 16:49:59 -0700 Subject: [PATCH 43/43] chore: secret scan in CodeBuild test (#9657) As it turns out, our secret scan was flagging the 'account' part of the mapping generated for the AWS Deep Learning Containers image repositories. Turn them into 'repositoryAccount' instead to silence the scanner. Also, actually enable the scanner to run correctly for PR builds as well. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- git-secrets-scan.sh | 6 +- .../lib/linux-gpu-build-image.ts | 4 +- ...arning-container-build-image.expected.json | 82 +++++++++---------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/git-secrets-scan.sh b/git-secrets-scan.sh index ed11ef5f4d890..95c2425ae5ec5 100755 --- a/git-secrets-scan.sh +++ b/git-secrets-scan.sh @@ -21,10 +21,10 @@ mkdir -p .tools git rev-parse --git-dir > /dev/null 2>&1 || { git init --quiet git add -A . - - # AWS config needs to be added to this fresh repository's config - .tools/git-secrets/git-secrets --register-aws } +# AWS config needs to be added to this repository's config +.tools/git-secrets/git-secrets --register-aws + .tools/git-secrets/git-secrets --scan echo "git-secrets scan ok" diff --git a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts index d9934e546f86d..b3f4c1d6dad61 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/linux-gpu-build-image.ts @@ -95,7 +95,7 @@ export class LinuxGpuBuildImage implements IBindableBuildImage { private readonly accountExpression: string; private constructor(private readonly repositoryName: string, tag: string, private readonly account: string | undefined) { - this.accountExpression = account ?? core.Fn.findInMap(mappingName, core.Aws.REGION, 'account'); + this.accountExpression = account ?? core.Fn.findInMap(mappingName, core.Aws.REGION, 'repositoryAccount'); this.imageId = `${this.accountExpression}.dkr.ecr.${core.Aws.REGION}.${core.Aws.URL_SUFFIX}/${repositoryName}:${tag}`; } @@ -109,7 +109,7 @@ export class LinuxGpuBuildImage implements IBindableBuildImage { // get the accounts from the region-info module const region2Accounts = RegionInfo.regionMap(FactName.DLC_REPOSITORY_ACCOUNT); for (const [region, account] of Object.entries(region2Accounts)) { - mapping[region] = { account }; + mapping[region] = { repositoryAccount: account }; } new core.CfnMapping(scopeStack, mappingName, { mapping }); } diff --git a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json index d5f641ecb1b9c..2c91da398b0a7 100644 --- a/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json +++ b/packages/@aws-cdk/aws-codebuild/test/integ.aws-deep-learning-container-build-image.expected.json @@ -138,7 +138,7 @@ { "Ref": "AWS::Region" }, - "account" + "repositoryAccount" ] }, ":repository/mxnet-training" @@ -180,7 +180,7 @@ { "Ref": "AWS::Region" }, - "account" + "repositoryAccount" ] }, ".dkr.ecr.", @@ -214,65 +214,65 @@ }, "Mappings": { "AwsDeepLearningContainersRepositoriesAccounts": { - "us-east-1": { - "account": "763104351884" + "ap-east-1": { + "repositoryAccount": "871362719292" }, - "us-east-2": { - "account": "763104351884" + "ap-northeast-1": { + "repositoryAccount": "763104351884" }, - "us-west-1": { - "account": "763104351884" + "ap-northeast-2": { + "repositoryAccount": "763104351884" }, - "us-west-2": { - "account": "763104351884" + "ap-south-1": { + "repositoryAccount": "763104351884" }, - "ca-central-1": { - "account": "763104351884" + "ap-southeast-1": { + "repositoryAccount": "763104351884" }, - "eu-west-1": { - "account": "763104351884" + "ap-southeast-2": { + "repositoryAccount": "763104351884" }, - "eu-west-2": { - "account": "763104351884" + "ca-central-1": { + "repositoryAccount": "763104351884" }, - "eu-west-3": { - "account": "763104351884" + "cn-north-1": { + "repositoryAccount": "727897471807" + }, + "cn-northwest-1": { + "repositoryAccount": "727897471807" }, "eu-central-1": { - "account": "763104351884" + "repositoryAccount": "763104351884" }, "eu-north-1": { - "account": "763104351884" - }, - "sa-east-1": { - "account": "763104351884" + "repositoryAccount": "763104351884" }, - "ap-south-1": { - "account": "763104351884" + "eu-west-1": { + "repositoryAccount": "763104351884" }, - "ap-northeast-1": { - "account": "763104351884" + "eu-west-2": { + "repositoryAccount": "763104351884" }, - "ap-northeast-2": { - "account": "763104351884" + "eu-west-3": { + "repositoryAccount": "763104351884" }, - "ap-southeast-1": { - "account": "763104351884" + "me-south-1": { + "repositoryAccount": "217643126080" }, - "ap-southeast-2": { - "account": "763104351884" + "sa-east-1": { + "repositoryAccount": "763104351884" }, - "ap-east-1": { - "account": "871362719292" + "us-east-1": { + "repositoryAccount": "763104351884" }, - "me-south-1": { - "account": "217643126080" + "us-east-2": { + "repositoryAccount": "763104351884" }, - "cn-north-1": { - "account": "727897471807" + "us-west-1": { + "repositoryAccount": "763104351884" }, - "cn-northwest-1": { - "account": "727897471807" + "us-west-2": { + "repositoryAccount": "763104351884" } } }