From 41940d3cfad289cbaed8ff60a21c6c9fa9aad532 Mon Sep 17 00:00:00 2001 From: CurtisEppel Date: Tue, 11 Aug 2020 17:57:31 +1000 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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 04/12] 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 05/12] 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 06/12] 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 07/12] 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 08/12] 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 09/12] 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 10/12] 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 11/12] 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 12/12] 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); });