From deccdebc43b4ff79c53ffa5a4171ef5a78f944c4 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 27 Oct 2021 18:12:33 +0200 Subject: [PATCH 01/13] chore(ec2): make examples (mostly) compile (#17183) There is one error left, jsii-rosetta doesn't support array indexing yet (`array[5]`). That's easy enough to add, so we're going to add that to Rosetta. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/README.md | 245 ++++++++++++------ .../@aws-cdk/aws-ec2/lib/security-group.ts | 2 +- packages/@aws-cdk/aws-ec2/lib/user-data.ts | 6 +- packages/@aws-cdk/aws-ec2/lib/volume.ts | 5 +- packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts | 2 + .../aws-ec2/rosetta/client-vpn.ts-fixture | 2 +- .../@aws-cdk/aws-ec2/rosetta/conns.ts-fixture | 26 -- .../aws-ec2/rosetta/default.ts-fixture | 8 +- 8 files changed, 177 insertions(+), 119 deletions(-) delete mode 100644 packages/@aws-cdk/aws-ec2/rosetta/conns.ts-fixture diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index f450e29dfcf20..ca30cc28fe9bd 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -93,17 +93,21 @@ must specify the environment where the stack will be deployed. You can gain full control over the availability zones selection strategy by overriding the Stack's [`get availabilityZones()`](https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/core/lib/stack.ts) method: -```ts +```text +// This example is only available in TypeScript + class MyStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + // ... + } + get availabilityZones(): string[] { return ['us-west-2a', 'us-west-2b']; } - constructor(scope: Construct, id: string, props?: StackProps) { - super(scope, id, props); - ... - } } ``` @@ -121,11 +125,13 @@ The example below will place the endpoint into two AZs (`us-east-1a` and `us-eas in Isolated subnets: ```ts -new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { +declare const vpc: ec2.Vpc; + +new ec2.InterfaceVpcEndpoint(this, 'VPC Endpoint', { vpc, - service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), + service: new ec2.InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), subnets: { - subnetType: SubnetType.ISOLATED, + subnetType: ec2.SubnetType.ISOLATED, availabilityZones: ['us-east-1a', 'us-east-1c'] } }); @@ -134,9 +140,13 @@ new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { You can also specify specific subnet objects for granular control: ```ts -new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { +declare const vpc: ec2.Vpc; +declare const subnet1: ec2.Subnet; +declare const subnet2: ec2.Subnet; + +new ec2.InterfaceVpcEndpoint(this, 'VPC Endpoint', { vpc, - service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), + service: new ec2.InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), subnets: { subnets: [subnet1, subnet2] } @@ -193,14 +203,16 @@ gets routed, pass `allowAllTraffic: false` and access the `NatInstanceProvider.connections` member after having passed it to the VPC: ```ts -const provider = NatProvider.instance({ - instanceType: /* ... */, +declare const instanceType: ec2.InstanceType; + +const provider = ec2.NatProvider.instance({ + instanceType, allowAllTraffic: false, }); -new Vpc(stack, 'TheVPC', { +new ec2.Vpc(this, 'TheVPC', { natGatewayProvider: provider, }); -provider.connections.allowFrom(Peer.ipv4('1.2.3.4/8'), Port.tcp(80)); +provider.connections.allowFrom(ec2.Peer.ipv4('1.2.3.4/8'), ec2.Port.tcp(80)); ``` ### Advanced Subnet Configuration @@ -284,6 +296,8 @@ DatabaseSubnet3 |`ISOLATED`|`10.0.6.32/28`|#3|Only routes within the VPC If you need access to the internet gateway, you can get its ID like so: ```ts +declare const vpc: ec2.Vpc; + const igwId = vpc.internetGatewayId; ``` @@ -305,18 +319,19 @@ Internet Gateway created for the public subnet - perhaps for routing a VPN connection - you can do so like this: ```ts -const vpc = ec2.Vpc(this, "VPC", { +const vpc = new ec2.Vpc(this, "VPC", { subnetConfiguration: [{ - subnetType: SubnetType.PUBLIC, + subnetType: ec2.SubnetType.PUBLIC, name: 'Public', },{ - subnetType: SubnetType.ISOLATED, + subnetType: ec2.SubnetType.ISOLATED, name: 'Isolated', }] -}) -(vpc.isolatedSubnets[0] as Subnet).addRoute("StaticRoute", { - routerId: vpc.internetGatewayId, - routerType: RouterType.GATEWAY, +}); + +(vpc.isolatedSubnets[0] as ec2.Subnet).addRoute("StaticRoute", { + routerId: vpc.internetGatewayId!, + routerType: ec2.RouterType.GATEWAY, destinationCidrBlock: "8.8.8.8/32", }) ``` @@ -412,7 +427,7 @@ following limitations: Using `Vpc.fromVpcAttributes()` looks like this: ```ts -const vpc = ec2.Vpc.fromVpcAttributes(stack, 'VPC', { +const vpc = ec2.Vpc.fromVpcAttributes(this, 'VPC', { vpcId: 'vpc-1234', availabilityZones: ['us-east-1a', 'us-east-1b'], @@ -423,7 +438,7 @@ const vpc = ec2.Vpc.fromVpcAttributes(stack, 'VPC', { privateSubnetIds: Fn.importListValue('PrivateSubnetIds', 2), // OR: split an imported string to a list of known length - isolatedSubnetIds: Fn.split(',', ssm.StringParameter.valueForStringParameter(stack, `MyParameter`), 2), + isolatedSubnetIds: Fn.split(',', ssm.StringParameter.valueForStringParameter(this, `MyParameter`), 2), }); ``` @@ -457,7 +472,11 @@ have security groups, you have to add an **Egress** rule to one Security Group, and an **Ingress** rule to the other. The connections object will automatically take care of this for you: -```ts fixture=conns +```ts +declare const loadBalancer: elbv2.ApplicationLoadBalancer; +declare const appFleet: autoscaling.AutoScalingGroup; +declare const dbFleet: autoscaling.AutoScalingGroup; + // Allow connections from anywhere loadBalancer.connections.allowFromAnyIpv4(ec2.Port.tcp(443), 'Allow inbound HTTPS'); @@ -472,7 +491,10 @@ appFleet.connections.allowTo(dbFleet, ec2.Port.tcp(443), 'App can call database' There are various classes that implement the connection peer part: -```ts fixture=conns +```ts +declare const appFleet: autoscaling.AutoScalingGroup; +declare const dbFleet: autoscaling.AutoScalingGroup; + // Simple connection peers let peer = ec2.Peer.ipv4('10.0.0.0/16'); peer = ec2.Peer.anyIpv4(); @@ -484,7 +506,11 @@ appFleet.connections.allowTo(peer, ec2.Port.tcp(443), 'Allow outbound HTTPS'); Any object that has a security group can itself be used as a connection peer: -```ts fixture=conns +```ts +declare const fleet1: autoscaling.AutoScalingGroup; +declare const fleet2: autoscaling.AutoScalingGroup; +declare const appFleet: autoscaling.AutoScalingGroup; + // These automatically create appropriate ingress and egress rules in both security groups fleet1.connections.allowTo(fleet2, ec2.Port.tcp(80), 'Allow between fleets'); @@ -518,7 +544,11 @@ If the object you're calling the peering method on has a default port associated For example: -```ts fixture=conns +```ts +declare const listener: elbv2.ApplicationListener; +declare const appFleet: autoscaling.AutoScalingGroup; +declare const rdsDatabase: rds.DatabaseCluster; + // Port implicit in listener listener.connections.allowDefaultPortFromAnyIpv4('Allow public'); @@ -637,9 +667,11 @@ By default, CDK will place a VPC endpoint in one subnet per AZ. If you wish to o use the `subnets` parameter as follows: ```ts -new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { +declare const vpc: ec2.Vpc; + +new ec2.InterfaceVpcEndpoint(this, 'VPC Endpoint', { vpc, - service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), + service: new ec2.InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), // Choose which availability zones to place the VPC endpoint in, based on // available AZs subnets: { @@ -654,9 +686,11 @@ AZs an endpoint service is available in, and will ensure the VPC endpoint is not These AZs will be stored in cdk.context.json. ```ts -new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { +declare const vpc: ec2.Vpc; + +new ec2.InterfaceVpcEndpoint(this, 'VPC Endpoint', { vpc, - service: new InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), + service: new ec2.InterfaceVpcEndpointService('com.amazonaws.vpce.us-east-1.vpce-svc-uuddlrlrbastrtsvc', 443), // Choose which availability zones to place the VPC endpoint in, based on // available AZs lookupSupportedAzs: true @@ -668,7 +702,12 @@ create VPC endpoints without having to configure name, ports, etc. For example, use in your VPC: ``` ts -new InterfaceVpcEndpoint(stack, 'VPC Endpoint', { vpc, service: InterfaceVpcEndpointAwsService.KEYSPACES }); +declare const vpc: ec2.Vpc; + +new ec2.InterfaceVpcEndpoint(this, 'VPC Endpoint', { + vpc, + service: ec2.InterfaceVpcEndpointAwsService.KEYSPACES, +}); ``` #### Security groups for interface VPC endpoints @@ -678,7 +717,9 @@ automatically allowed from the VPC CIDR. Use the `connections` object to allow traffic to flow to the endpoint: -```ts fixture=conns +```ts +declare const myEndpoint: ec2.InterfaceVpcEndpoint; + myEndpoint.connections.allowDefaultPortFromAnyIpv4(); ``` @@ -689,10 +730,13 @@ Alternatively, existing security groups can be used by specifying the `securityG A VPC endpoint service enables you to expose a Network Load Balancer(s) as a provider service to consumers, who connect to your service over a VPC endpoint. You can restrict access to your service via allowed principals (anything that extends ArnPrincipal), and require that new connections be manually accepted. ```ts -new VpcEndpointService(this, 'EndpointService', { +declare const networkLoadBalancer1: elbv2.NetworkLoadBalancer; +declare const networkLoadBalancer2: elbv2.NetworkLoadBalancer; + +new ec2.VpcEndpointService(this, 'EndpointService', { vpcEndpointServiceLoadBalancers: [networkLoadBalancer1, networkLoadBalancer2], acceptanceRequired: true, - allowedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')] + allowedPrincipals: [new iam.ArnPrincipal('arn:aws:iam::123456789012:root')] }); ``` @@ -700,9 +744,11 @@ Endpoint services support private DNS, which makes it easier for clients to conn You can enable private DNS on an endpoint service like so: ```ts -import { VpcEndpointServiceDomainName } from '@aws-cdk/aws-route53'; +import { HostedZone, VpcEndpointServiceDomainName } from '@aws-cdk/aws-route53'; +declare const zone: HostedZone; +declare const vpces: ec2.VpcEndpointService; -new VpcEndpointServiceDomainName(stack, 'EndpointDomain', { +new VpcEndpointServiceDomainName(this, 'EndpointDomain', { endpointService: vpces, domainName: 'my-stuff.aws-cdk.dev', publicHostedZone: zone, @@ -796,7 +842,15 @@ For the full set of capabilities of this system, see the documentation for Here is an example of applying some configuration to an instance: ```ts +declare const vpc: ec2.Vpc; +declare const instanceType: ec2.InstanceType; +declare const machineImage: ec2.IMachineImage; + new ec2.Instance(this, 'Instance', { + vpc, + instanceType, + machineImage, + // Showing the most complex setup, if you have simpler requirements // you can use `CloudFormationInit.fromElements()`. init: ec2.CloudFormationInit.fromConfigSets({ @@ -812,9 +866,9 @@ new ec2.Instance(this, 'Instance', { config: new ec2.InitConfig([ // Create a JSON file from tokens (can also create other files) ec2.InitFile.fromObject('/etc/stack.json', { - stackId: stack.stackId, - stackName: stack.stackName, - region: stack.region, + stackId: Stack.of(this).stackId, + stackName: Stack.of(this).stackName, + region: Stack.of(this).region, }), // Create a group and user @@ -834,10 +888,10 @@ new ec2.Instance(this, 'Instance', { timeout: Duration.minutes(30), // Optional, whether to include the --url argument when running cfn-init and cfn-signal commands (false by default) - includeUrl: true + includeUrl: true, // Optional, whether to include the --role argument when running cfn-init and cfn-signal commands (false by default) - includeRole: true + includeRole: true, }, }); ``` @@ -849,11 +903,13 @@ config writes a config file for nginx, extracts an archive to the root directory restarts nginx so that it picks up the new config and files: ```ts +declare const myBucket: s3.Bucket; + const handle = new ec2.InitServiceRestartHandle(); ec2.CloudFormationInit.fromElements( ec2.InitFile.fromString('/etc/nginx/nginx.conf', '...', { serviceRestartHandles: [handle] }), - ec2.InitSource.fromBucket('/var/www/html', myBucket, 'html.zip', { serviceRestartHandles: [handle] }), + ec2.InitSource.fromS3Object('/var/www/html', myBucket, 'html.zip', { serviceRestartHandles: [handle] }), ec2.InitService.enable('nginx', { serviceRestartHandle: handle, }) @@ -887,16 +943,16 @@ with the command `aws ec2-instance-connect send-ssh-public-key` to provide your EBS volume for the bastion host can be encrypted like: -```ts - const host = new ec2.BastionHostLinux(stack, 'BastionHost', { - vpc, - blockDevices: [{ - deviceName: 'EBSBastionHost', - volume: BlockDeviceVolume.ebs(10, { - encrypted: true, - }), - }], - }); +```ts fixture=with-vpc +const host = new ec2.BastionHostLinux(this, 'BastionHost', { + vpc, + blockDevices: [{ + deviceName: 'EBSBastionHost', + volume: ec2.BlockDeviceVolume.ebs(10, { + encrypted: true, + }), + }], +}); ``` ### Block Devices @@ -906,8 +962,17 @@ root device (`/dev/sda1`) size to 50 GiB, and adds another EBS-backed device map size: ```ts +declare const vpc: ec2.Vpc; +declare const instanceType: ec2.InstanceType; +declare const machineImage: ec2.IMachineImage; + new ec2.Instance(this, 'Instance', { + vpc, + instanceType, + machineImage, + // ... + blockDevices: [ { deviceName: '/dev/sda1', @@ -931,15 +996,12 @@ A notable restriction is that a Volume can only be attached to instances in the The following demonstrates how to create a 500 GiB encrypted Volume in the `us-west-2a` availability zone, and give a role the ability to attach that Volume to a specific instance: ```ts -const instance = new ec2.Instance(this, 'Instance', { - // ... -}); -const role = new iam.Role(stack, 'SomeRole', { - assumedBy: new iam.AccountRootPrincipal(), -}); +declare const instance: ec2.Instance; +declare const role: iam.Role; + const volume = new ec2.Volume(this, 'Volume', { availabilityZone: 'us-west-2a', - size: cdk.Size.gibibytes(500), + size: Size.gibibytes(500), encrypted: true, }); @@ -952,12 +1014,8 @@ If you need to grant an instance the ability to attach/detach an EBS volume to/f will lead to an unresolvable circular reference between the instance role and the instance. In this case, use `grantAttachVolumeByResourceTag` and `grantDetachVolumeByResourceTag` as follows: ```ts -const instance = new ec2.Instance(this, 'Instance', { - // ... -}); -const volume = new ec2.Volume(this, 'Volume', { - // ... -}); +declare const instance: ec2.Instance; +declare const volume: ec2.Volume; const attachGrant = volume.grantAttachVolumeByResourceTag(instance.grantPrincipal, [instance]); const detachGrant = volume.grantDetachVolumeByResourceTag(instance.grantPrincipal, [instance]); @@ -973,12 +1031,9 @@ to attach and detach your Volumes to/from instances, and how to format them for The following is a sample skeleton of EC2 UserData that can be used to attach a Volume to the Linux instance that it is running on: ```ts -const volume = new ec2.Volume(this, 'Volume', { - // ... -}); -const instance = new ec2.Instance(this, 'Instance', { - // ... -}); +declare const instance: ec2.Instance; +declare const volume: ec2.Volume; + volume.grantAttachVolumeByResourceTag(instance.grantPrincipal, [instance]); const targetDevice = '/dev/xvdz'; instance.userData.addCommands( @@ -1005,9 +1060,18 @@ To do this for a single `Instance`, you can use the `requireImdsv2` property. The example below demonstrates IMDSv2 being required on a single `Instance`: ```ts +declare const vpc: ec2.Vpc; +declare const instanceType: ec2.InstanceType; +declare const machineImage: ec2.IMachineImage; + new ec2.Instance(this, 'Instance', { - requireImdsv2: true, + vpc, + instanceType, + machineImage, + // ... + + requireImdsv2: true, }); ``` @@ -1018,7 +1082,7 @@ The following example demonstrates how to use the `InstanceRequireImdsv2Aspect` ```ts const aspect = new ec2.InstanceRequireImdsv2Aspect(); -Aspects.of(stack).add(aspect); +Aspects.of(this).add(aspect); ``` ## VPC Flow Logs @@ -1030,6 +1094,8 @@ By default a flow log will be created with CloudWatch Logs as the destination. You can create a flow log like this: ```ts +declare const vpc: ec2.Vpc; + new ec2.FlowLog(this, 'FlowLog', { resourceType: ec2.FlowLogResourceType.fromVpc(vpc) }) @@ -1066,6 +1132,8 @@ If you want to customize any of the destination resources you can provide your o *CloudWatch Logs* ```ts +declare const vpc: ec2.Vpc; + const logGroup = new logs.LogGroup(this, 'MyCustomLogGroup'); const role = new iam.Role(this, 'MyCustomRole', { @@ -1081,6 +1149,7 @@ new ec2.FlowLog(this, 'FlowLog', { *S3* ```ts +declare const vpc: ec2.Vpc; const bucket = new s3.Bucket(this, 'MyCustomBucket'); @@ -1103,10 +1172,14 @@ User data enables you to run a script when your instances start up. In order to A user data could be configured to run a script found in an asset through the following: ```ts -const asset = new Asset(this, 'Asset', {path: path.join(__dirname, 'configure.sh')}); -const instance = new ec2.Instance(this, 'Instance', { - // ... - }); +import { Asset } from '@aws-cdk/aws-s3-assets'; + +declare const instance: ec2.Instance; + +const asset = new Asset(this, 'Asset', { + path: './configure.sh' +}); + const localPath = instance.userData.addS3DownloadCommand({ bucket:asset.bucket, bucketKey:asset.s3ObjectKey, @@ -1116,7 +1189,7 @@ instance.userData.addExecuteFileCommand({ filePath:localPath, arguments: '--verbose -y' }); -asset.grantRead( instance.role ); +asset.grantRead(instance.role); ``` ### Multipart user data @@ -1152,7 +1225,7 @@ multipartUserData.addPart(ec2.MultipartBody.fromUserData(bootHookConf, 'text/clo // Execute the rest of setup multipartUserData.addPart(ec2.MultipartBody.fromUserData(setupCommands)); -new ec2.LaunchTemplate(stack, '', { +new ec2.LaunchTemplate(this, '', { userData: multipartUserData, blockDevices: [ // Block device configuration rest @@ -1172,7 +1245,7 @@ method on `MultipartUserData` with the `makeDefault` argument set to `true`: ```ts const multipartUserData = new ec2.MultipartUserData(); const commandsUserData = ec2.UserData.forLinux(); -multipartUserData.addUserDataPart(commandsUserData, MultipartBody.SHELL_SCRIPT, true); +multipartUserData.addUserDataPart(commandsUserData, ec2.MultipartBody.SHELL_SCRIPT, true); // Adding commands to the multipartUserData adds them to commandsUserData, and vice-versa. multipartUserData.addCommands('touch /root/multi.txt'); @@ -1193,14 +1266,14 @@ Importing an existing subnet looks like this: ```ts // Supply all properties -const subnet = Subnet.fromSubnetAttributes(this, 'SubnetFromAttributes', { +const subnet1 = ec2.Subnet.fromSubnetAttributes(this, 'SubnetFromAttributes', { subnetId: 's-1234', availabilityZone: 'pub-az-4465', routeTableId: 'rt-145' }); // Supply only subnet id -const subnet = Subnet.fromSubnetId(this, 'SubnetFromId', 's-1234'); +const subnet2 = ec2.Subnet.fromSubnetId(this, 'SubnetFromId', 's-1234'); ``` ## Launch Templates @@ -1214,10 +1287,10 @@ an instance. For information on Launch Templates please see the The following demonstrates how to create a launch template with an Amazon Machine Image, and security group. ```ts -const vpc = new ec2.Vpc(...); -// ... +declare const vpc: ec2.Vpc; + const template = new ec2.LaunchTemplate(this, 'LaunchTemplate', { - machineImage: new ec2.AmazonMachineImage(), + machineImage: ec2.MachineImage.latestAmazonLinux(), securityGroup: new ec2.SecurityGroup(this, 'LaunchTemplateSG', { vpc: vpc, }), diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index 2c01da7aef943..54695f2d17b71 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -308,7 +308,7 @@ export interface SecurityGroupImportOptions { * you would import it like this: * * ```ts - * const securityGroup = SecurityGroup.fromSecurityGroupId(this, 'SG', 'sg-12345', { + * const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(this, 'SG', 'sg-12345', { * mutable: false * }); * ``` diff --git a/packages/@aws-cdk/aws-ec2/lib/user-data.ts b/packages/@aws-cdk/aws-ec2/lib/user-data.ts index 14b94d2d2ad4a..1e92eb888e6f8 100644 --- a/packages/@aws-cdk/aws-ec2/lib/user-data.ts +++ b/packages/@aws-cdk/aws-ec2/lib/user-data.ts @@ -489,7 +489,11 @@ export class MultipartUserData extends UserData { * If `makeDefault` is false, then this is the same as calling: * * ```ts - * multiPart.addPart(MultipartBody.fromUserData(userData, contentType)); + * declare const multiPart: ec2.MultipartUserData; + * declare const userData: ec2.UserData; + * declare const contentType: string; + * + * multiPart.addPart(ec2.MultipartBody.fromUserData(userData, contentType)); * ``` * * An undefined `makeDefault` defaults to either: diff --git a/packages/@aws-cdk/aws-ec2/lib/volume.ts b/packages/@aws-cdk/aws-ec2/lib/volume.ts index a25ca459b7c63..87e92b3f5006a 100644 --- a/packages/@aws-cdk/aws-ec2/lib/volume.ts +++ b/packages/@aws-cdk/aws-ec2/lib/volume.ts @@ -19,7 +19,7 @@ export interface BlockDevice { /** * The device name exposed to the EC2 instance * - * @example '/dev/sdh', 'xvdh' + * For example, a value like `/dev/sdh`, `xvdh`. * * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html */ @@ -28,8 +28,7 @@ export interface BlockDevice { /** * Defines the block device volume, to be either an Amazon EBS volume or an ephemeral instance store volume * - * @example BlockDeviceVolume.ebs(15), BlockDeviceVolume.ephemeral(0) - * + * For example, a value like `BlockDeviceVolume.ebs(15)`, `BlockDeviceVolume.ephemeral(0)`. */ readonly volume: BlockDeviceVolume; diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts index de64072868391..3282da410d09a 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts @@ -121,6 +121,8 @@ export interface GatewayVpcEndpointOptions { * @default - All subnets in the VPC * @example * + * declare const vpc: ec2.Vpc; + * * vpc.addGatewayEndpoint('DynamoDbEndpoint', { * service: ec2.GatewayVpcEndpointAwsService.DYNAMODB, * // Add only to ISOLATED subnets diff --git a/packages/@aws-cdk/aws-ec2/rosetta/client-vpn.ts-fixture b/packages/@aws-cdk/aws-ec2/rosetta/client-vpn.ts-fixture index 4886d590211df..34c83a31ced35 100644 --- a/packages/@aws-cdk/aws-ec2/rosetta/client-vpn.ts-fixture +++ b/packages/@aws-cdk/aws-ec2/rosetta/client-vpn.ts-fixture @@ -9,7 +9,7 @@ class Fixture extends Stack { const vpc = new ec2.Vpc(this, 'VPC'); const samlProvider = new iam.SamlProvider(this, 'Provider', { - metadataDocument: SamlMetadataDocument.fromXml('xml'), + metadataDocument: iam.SamlMetadataDocument.fromXml('xml'), }) /// here diff --git a/packages/@aws-cdk/aws-ec2/rosetta/conns.ts-fixture b/packages/@aws-cdk/aws-ec2/rosetta/conns.ts-fixture deleted file mode 100644 index f29d9a1816a6e..0000000000000 --- a/packages/@aws-cdk/aws-ec2/rosetta/conns.ts-fixture +++ /dev/null @@ -1,26 +0,0 @@ -// Fixture with fake connectables -import { Construct, Stack } from '@aws-cdk/core'; -import ec2 = require('@aws-cdk/aws-ec2'); - -class Fixture extends Stack { - constructor(scope: Construct, id: string) { - super(scope, id); - - const vpc = new ec2.Vpc(this, 'VPC'); - - const loadBalancer = new FakeConnectable(); - const appFleet = new FakeConnectable(); - const dbFleet = new FakeConnectable(); - const rdsDatabase = new FakeConnectable(); - const fleet1 = new FakeConnectable(); - const fleet2 = new FakeConnectable(); - const listener = new FakeConnectable(); - const myEndpoint = new FakeConnectable(); - - /// here - } -} - -class FakeConnectable implements ec2.IConnectable { - public readonly connections = new ec2.Connections({ securityGroups: [] }); -} diff --git a/packages/@aws-cdk/aws-ec2/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-ec2/rosetta/default.ts-fixture index d4ecd7e92a6f1..df2d29f125b46 100644 --- a/packages/@aws-cdk/aws-ec2/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/aws-ec2/rosetta/default.ts-fixture @@ -1,7 +1,13 @@ // Fixture with packages imported, but nothing else -import { Construct, Stack } from '@aws-cdk/core'; +import { Aspects, Construct, Duration, Fn, Size, Stack, StackProps } from '@aws-cdk/core'; import ec2 = require('@aws-cdk/aws-ec2'); +import s3 = require('@aws-cdk/aws-s3'); import iam = require('@aws-cdk/aws-iam'); +import logs = require('@aws-cdk/aws-logs'); +import ssm = require('@aws-cdk/aws-ssm'); +import autoscaling = require('@aws-cdk/aws-autoscaling'); +import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); +import rds = require('@aws-cdk/aws-rds'); class Fixture extends Stack { constructor(scope: Construct, id: string) { From 6aa86d590d5e06c64677161d970eb39a77f8fd99 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 27 Oct 2021 19:04:44 +0200 Subject: [PATCH 02/13] chore(elbv2): make examples compile (#17162) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-elasticloadbalancingv2/README.md | 131 +++++++++++------- .../rosetta/default.ts-fixture | 17 +++ 2 files changed, 100 insertions(+), 48 deletions(-) create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2/rosetta/default.ts-fixture diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index f3d23b5e827cf..34755353fb202 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -26,13 +26,10 @@ You define an application load balancer by creating an instance of and adding Targets to the Listener: ```ts -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import { AutoScalingGroup } from '@aws-cdk/aws-autoscaling'; +declare const asg: AutoScalingGroup; -// ... - -const vpc = new ec2.Vpc(...); +declare const vpc: ec2.Vpc; // Create the load balancer in a VPC. 'internetFacing' is 'false' // by default, which creates an internal load balancer. @@ -54,7 +51,6 @@ const listener = lb.addListener('Listener', { // Create an AutoScaling group and add it as a load balancing // target to the listener. -const asg = new AutoScalingGroup(...); listener.addTargets('ApplicationFleet', { port: 8080, targets: [asg] @@ -68,14 +64,16 @@ One (or more) security groups can be associated with the load balancer; if a security group isn't provided, one will be automatically created. ```ts -const securityGroup1 = new ec2.SecurityGroup(stack, 'SecurityGroup1', { vpc }); +declare const vpc: ec2.Vpc; + +const securityGroup1 = new ec2.SecurityGroup(this, 'SecurityGroup1', { vpc }); const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', { vpc, internetFacing: true, securityGroup: securityGroup1, // Optional - will be automatically created otherwise }); -const securityGroup2 = new ec2.SecurityGroup(stack, 'SecurityGroup2', { vpc }); +const securityGroup2 = new ec2.SecurityGroup(this, 'SecurityGroup2', { vpc }); lb.addSecurityGroup(securityGroup2); ``` @@ -87,11 +85,14 @@ AutoScalingGroup only if the requested host in the request is either for `example.com/ok` or `example.com/path`: ```ts +declare const listener: elbv2.ApplicationListener; +declare const asg: autoscaling.AutoScalingGroup; + listener.addTargets('Example.Com Fleet', { priority: 10, conditions: [ - ListenerCondition.hostHeaders(['example.com']), - ListenerCondition.pathPatterns(['/ok', '/path']), + elbv2.ListenerCondition.hostHeaders(['example.com']), + elbv2.ListenerCondition.pathPatterns(['/ok', '/path']), ], port: 8080, targets: [asg] @@ -149,12 +150,14 @@ Balancer that the other two convenience methods don't: Here's an example of serving a fixed response at the `/ok` URL: ```ts +declare const listener: elbv2.ApplicationListener; + listener.addAction('Fixed', { priority: 10, conditions: [ - ListenerCondition.pathPatterns(['/ok']), + elbv2.ListenerCondition.pathPatterns(['/ok']), ], - action: ListenerAction.fixedResponse(200, { + action: elbv2.ListenerAction.fixedResponse(200, { contentType: elbv2.ContentType.TEXT_PLAIN, messageBody: 'OK', }) @@ -164,12 +167,21 @@ listener.addAction('Fixed', { Here's an example of using OIDC authentication before forwarding to a TargetGroup: ```ts +declare const listener: elbv2.ApplicationListener; +declare const myTargetGroup: elbv2.ApplicationTargetGroup; + listener.addAction('DefaultAction', { - action: ListenerAction.authenticateOidc({ + action: elbv2.ListenerAction.authenticateOidc({ authorizationEndpoint: 'https://example.com/openid', // Other OIDC properties here - // ... - next: ListenerAction.forward([myTargetGroup]), + clientId: '...', + clientSecret: SecretValue.secretsManager('...'), + issuer: '...', + tokenEndpoint: '...', + userInfoEndpoint: '...', + + // Next + next: elbv2.ListenerAction.forward([myTargetGroup]), }), }); ``` @@ -177,6 +189,8 @@ listener.addAction('DefaultAction', { If you just want to redirect all incoming traffic on one port to another port, you can use the following code: ```ts +declare const lb: elbv2.ApplicationLoadBalancer; + lb.addRedirect({ sourceProtocol: elbv2.ApplicationProtocol.HTTPS, sourcePort: 8443, @@ -196,9 +210,8 @@ Network Load Balancers are defined in a similar way to Application Load Balancers: ```ts -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; -import * as autoscaling from '@aws-cdk/aws-autoscaling'; +declare const vpc: ec2.Vpc; +declare const asg: autoscaling.AutoScalingGroup; // Create the load balancer in a VPC. 'internetFacing' is 'false' // by default, which creates an internal load balancer. @@ -243,6 +256,10 @@ and add it to the listener by calling `addTargetGroups` instead of `addTargets`. `addTargets()` will always return the Target Group it just created for you: ```ts +declare const listener: elbv2.NetworkListener; +declare const asg1: autoscaling.AutoScalingGroup; +declare const asg2: autoscaling.AutoScalingGroup; + const group = listener.addTargets('AppFleet', { port: 443, targets: [asg1], @@ -258,19 +275,21 @@ By default, an Application Load Balancer routes each request independently to a Application Load Balancers support both duration-based cookies (`lb_cookie`) and application-based cookies (`app_cookie`). The key to managing sticky sessions is determining how long your load balancer should consistently route the user's request to the same target. Sticky sessions are enabled at the target group level. You can use a combination of duration-based stickiness, application-based stickiness, and no stickiness across all of your target groups. ```ts +declare const vpc: ec2.Vpc; + // Target group with duration-based stickiness with load-balancer generated cookie -const tg1 = new elbv2.ApplicationTargetGroup(stack, 'TG1', { +const tg1 = new elbv2.ApplicationTargetGroup(this, 'TG1', { targetType: elbv2.TargetType.INSTANCE, port: 80, - stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieDuration: Duration.minutes(5), vpc, }); // Target group with application-based stickiness -const tg2 = new elbv2.ApplicationTargetGroup(stack, 'TG2', { +const tg2 = new elbv2.ApplicationTargetGroup(this, 'TG2', { targetType: elbv2.TargetType.INSTANCE, port: 80, - stickinessCookieDuration: cdk.Duration.minutes(5), + stickinessCookieDuration: Duration.minutes(5), stickinessCookieName: 'MyDeliciousCookie', vpc, }); @@ -283,7 +302,9 @@ For more information see: https://docs.aws.amazon.com/elasticloadbalancing/lates By default, Application Load Balancers send requests to targets using HTTP/1.1. You can use the [protocol version](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html#target-group-protocol-version) to send requests to targets using HTTP/2 or gRPC. ```ts -const tg = new elbv2.ApplicationTargetGroup(stack, 'TG', { +declare const vpc: ec2.Vpc; + +const tg = new elbv2.ApplicationTargetGroup(this, 'TG', { targetType: elbv2.TargetType.IP, port: 50051, protocol: elbv2.ApplicationProtocol.HTTP, @@ -303,11 +324,10 @@ To use a Lambda Function as a target, use the integration class in the ```ts import * as lambda from '@aws-cdk/aws-lambda'; -import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as targets from '@aws-cdk/aws-elasticloadbalancingv2-targets'; -const lambdaFunction = new lambda.Function(...); -const lb = new elbv2.ApplicationLoadBalancer(...); +declare const lambdaFunction: lambda.Function; +declare const lb: elbv2.ApplicationLoadBalancer; const listener = lb.addListener('Listener', { port: 80 }); listener.addTargets('Targets', { @@ -329,11 +349,12 @@ To use a single application load balancer as a target for the network load balan `@aws-cdk/aws-elasticloadbalancingv2-targets` package: ```ts -import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as targets from '@aws-cdk/aws-elasticloadbalancingv2-targets'; import * as ecs from '@aws-cdk/aws-ecs'; import * as patterns from '@aws-cdk/aws-ecs-patterns'; +declare const vpc: ec2.Vpc; + const task = new ecs.FargateTaskDefinition(this, 'Task', { cpu: 256, memoryLimitMiB: 512 }); task.addContainer('nginx', { image: ecs.ContainerImage.fromRegistry('public.ecr.aws/nginx/nginx:latest'), @@ -369,12 +390,15 @@ Only the network load balancer is allowed to add the application load balancer a Health checks are configured upon creation of a target group: ```ts +declare const listener: elbv2.ApplicationListener; +declare const asg: autoscaling.AutoScalingGroup; + listener.addTargets('AppFleet', { port: 8080, targets: [asg], healthCheck: { path: '/ping', - interval: cdk.Duration.minutes(1), + interval: Duration.minutes(1), } }); ``` @@ -388,15 +412,19 @@ you're routing traffic to, the security group already allows the traffic. If not, you will have to configure the security groups appropriately: ```ts +declare const lb: elbv2.ApplicationLoadBalancer; +declare const listener: elbv2.ApplicationListener; +declare const asg: autoscaling.AutoScalingGroup; + listener.addTargets('AppFleet', { port: 8080, targets: [asg], healthCheck: { - port: 8088, + port: '8088', } }); -listener.connections.allowFrom(lb, ec2.Port.tcp(8088)); +asg.connections.allowFrom(lb, ec2.Port.tcp(8088)); ``` ## Using a Load Balancer from a different Stack @@ -424,12 +452,15 @@ call functions on the load balancer and should return metadata about the load balancing target: ```ts -public attachToApplicationTargetGroup(targetGroup: ApplicationTargetGroup): LoadBalancerTargetProps { - targetGroup.registerConnectable(...); - return { - targetType: TargetType.Instance | TargetType.Ip - targetJson: { id: ..., port: ... }, - }; +class MyTarget implements elbv2.IApplicationLoadBalancerTarget { + public attachToApplicationTargetGroup(targetGroup: elbv2.ApplicationTargetGroup): elbv2.LoadBalancerTargetProps { + // If we need to add security group rules + // targetGroup.registerConnectable(...); + return { + targetType: elbv2.TargetType.IP, + targetJson: { id: '1.2.3.4', port: 8080 }, + }; + } } ``` @@ -445,12 +476,16 @@ group rules. If your load balancer target requires that the TargetGroup has been associated with a LoadBalancer before registration can happen (such as is the case for ECS Services for example), take a resource dependency on -`targetGroup.loadBalancerDependency()` as follows: +`targetGroup.loadBalancerAttached` as follows: ```ts +declare const resource: Resource; +declare const targetGroup: elbv2.ApplicationTargetGroup; + // Make sure that the listener has been created, and so the TargetGroup // has been associated with the LoadBalancer, before 'resource' is created. -resourced.addDependency(targetGroup.loadBalancerDependency()); + +Node.of(resource).addDependency(targetGroup.loadBalancerAttached); ``` ## Looking up Load Balancers and Listeners @@ -478,15 +513,15 @@ provide more specific criteria. **Look up a Application Load Balancer by ARN** ```ts -const loadBalancer = ApplicationLoadBalancer.fromLookup(stack, 'ALB', { - loadBalancerArn: YOUR_ALB_ARN, +const loadBalancer = elbv2.ApplicationLoadBalancer.fromLookup(this, 'ALB', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-east-2:123456789012:loadbalancer/app/my-load-balancer/1234567890123456', }); ``` **Look up an Application Load Balancer by tags** ```ts -const loadBalancer = ApplicationLoadBalancer.fromLookup(stack, 'ALB', { +const loadBalancer = elbv2.ApplicationLoadBalancer.fromLookup(this, 'ALB', { loadBalancerTags: { // Finds a load balancer matching all tags. some: 'tag', @@ -512,9 +547,9 @@ criteria. **Look up a Listener by associated Load Balancer, Port, and Protocol** ```ts -const listener = ApplicationListener.fromLookup(stack, 'ALBListener', { - loadBalancerArn: YOUR_ALB_ARN, - listenerProtocol: ApplicationProtocol.HTTPS, +const listener = elbv2.ApplicationListener.fromLookup(this, 'ALBListener', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-east-2:123456789012:loadbalancer/app/my-load-balancer/1234567890123456', + listenerProtocol: elbv2.ApplicationProtocol.HTTPS, listenerPort: 443, }); ``` @@ -522,11 +557,11 @@ const listener = ApplicationListener.fromLookup(stack, 'ALBListener', { **Look up a Listener by associated Load Balancer Tag, Port, and Protocol** ```ts -const listener = ApplicationListener.fromLookup(stack, 'ALBListener', { +const listener = elbv2.ApplicationListener.fromLookup(this, 'ALBListener', { loadBalancerTags: { Cluster: 'MyClusterName', }, - listenerProtocol: ApplicationProtocol.HTTPS, + listenerProtocol: elbv2.ApplicationProtocol.HTTPS, listenerPort: 443, }); ``` @@ -534,11 +569,11 @@ const listener = ApplicationListener.fromLookup(stack, 'ALBListener', { **Look up a Network Listener by associated Load Balancer Tag, Port, and Protocol** ```ts -const listener = NetworkListener.fromLookup(stack, 'ALBListener', { +const listener = elbv2.NetworkListener.fromLookup(this, 'ALBListener', { loadBalancerTags: { Cluster: 'MyClusterName', }, - listenerProtocol: Protocol.TCP, + listenerProtocol: elbv2.Protocol.TCP, listenerPort: 12345, }); ``` diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-elasticloadbalancingv2/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..8a21c6ec4d9a6 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/rosetta/default.ts-fixture @@ -0,0 +1,17 @@ +// Fixture with packages imported, but nothing else +import { Construct, Node } from 'constructs'; +import { CfnOutput, Stack, Duration, Resource, SecretValue } from '@aws-cdk/core'; +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as autoscaling from '@aws-cdk/aws-autoscaling'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} + + + From d298696a7d8978296a34294484cea80f91ebe880 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Wed, 27 Oct 2021 18:55:18 +0100 Subject: [PATCH 03/13] feat(core): Docker tags can be prefixed (#17028) This adds a container image equivalent of the `bucketPrefix` option for file assets. CDK assets works very well to make deploying applications easy, but I often find the contents of the S3 bucket and ECR repo to be a mess of alphabetti spaghetti over time. These options should help to provide some context in future cleanup operations. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../stack-synthesizers/default-synthesizer.ts | 19 +++++++++++++-- .../new-style-synthesis.test.ts | 24 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts index aae69e36ef24e..d8e1f8818abc4 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/default-synthesizer.ts @@ -168,11 +168,20 @@ export interface DefaultStackSynthesizerProps { /** * bucketPrefix to use while storing S3 Assets * - * * @default - DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PREFIX */ readonly bucketPrefix?: string; + /** + * A prefix to use while tagging and uploading Docker images to ECR. + * + * This does not add any separators - the source hash will be appended to + * this string directly. + * + * @default - DefaultStackSynthesizer.DEFAULT_DOCKER_ASSET_PREFIX + */ + readonly dockerTagPrefix?: string; + /** * Bootstrap stack version SSM parameter. * @@ -242,6 +251,10 @@ export class DefaultStackSynthesizer extends StackSynthesizer { * Default file asset prefix */ public static readonly DEFAULT_FILE_ASSET_PREFIX = ''; + /** + * Default Docker asset prefix + */ + public static readonly DEFAULT_DOCKER_ASSET_PREFIX = ''; /** * Default bootstrap stack version SSM parameter. @@ -258,6 +271,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer { private lookupRoleArn?: string; private qualifier?: string; private bucketPrefix?: string; + private dockerTagPrefix?: string; private bootstrapStackVersionSsmParameter?: string; private readonly files: NonNullable = {}; @@ -319,6 +333,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer { this.imageAssetPublishingRoleArn = specialize(this.props.imageAssetPublishingRoleArn ?? DefaultStackSynthesizer.DEFAULT_IMAGE_ASSET_PUBLISHING_ROLE_ARN); this.lookupRoleArn = specialize(this.props.lookupRoleArn ?? DefaultStackSynthesizer.DEFAULT_LOOKUP_ROLE_ARN); this.bucketPrefix = specialize(this.props.bucketPrefix ?? DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PREFIX); + this.dockerTagPrefix = specialize(this.props.dockerTagPrefix ?? DefaultStackSynthesizer.DEFAULT_DOCKER_ASSET_PREFIX); this.bootstrapStackVersionSsmParameter = replaceAll( this.props.bootstrapStackVersionSsmParameter ?? DefaultStackSynthesizer.DEFAULT_BOOTSTRAP_STACK_VERSION_SSM_PARAMETER, '${Qualifier}', @@ -372,7 +387,7 @@ export class DefaultStackSynthesizer extends StackSynthesizer { assertBound(this.repositoryName); validateDockerImageAssetSource(asset); - const imageTag = asset.sourceHash; + const imageTag = this.dockerTagPrefix + asset.sourceHash; // Add to manifest this.dockerImages[asset.sourceHash] = { diff --git a/packages/@aws-cdk/core/test/stack-synthesis/new-style-synthesis.test.ts b/packages/@aws-cdk/core/test/stack-synthesis/new-style-synthesis.test.ts index 3a8d8c1e60b31..80303a4bbcf22 100644 --- a/packages/@aws-cdk/core/test/stack-synthesis/new-style-synthesis.test.ts +++ b/packages/@aws-cdk/core/test/stack-synthesis/new-style-synthesis.test.ts @@ -337,6 +337,30 @@ describe('new style synthesis', () => { }); + test('synthesis with dockerPrefix', () => { + // GIVEN + const myapp = new App(); + + // WHEN + const mystack = new Stack(myapp, 'mystack-dockerPrefix', { + synthesizer: new DefaultStackSynthesizer({ + dockerTagPrefix: 'test-prefix-', + }), + }); + + mystack.synthesizer.addDockerImageAsset({ + directoryName: 'some-folder', + sourceHash: 'docker-asset-hash', + }); + + const asm = myapp.synth(); + + // THEN + const manifest = readAssetManifest(getAssetManifest(asm)); + const imageTag = manifest.dockerImages?.['docker-asset-hash']?.destinations?.['current_account-current_region'].imageTag; + expect(imageTag).toEqual('test-prefix-docker-asset-hash'); + }); + test('cannot use same synthesizer for multiple stacks', () => { // GIVEN const synthesizer = new DefaultStackSynthesizer(); From e5095b2cbda7422bd6e67aab6ad949294b0b8ef2 Mon Sep 17 00:00:00 2001 From: niku <10890+niku@users.noreply.github.com> Date: Thu, 28 Oct 2021 03:48:30 +0900 Subject: [PATCH 04/13] chore(cx-api): return type of futureFlagDefault is incorrect (#17026) If invalid flag were given to futureFlagDefault, it returns `undefined`. As you see in changed files, I don't modify production codes. I only fix return type of the `futureFlagDefault` and add a test to describe when it runs into. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/cx-api/lib/features.ts | 2 +- packages/@aws-cdk/cx-api/test/features.test.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 986be7f4e136b..37c9aace0ce86 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -220,6 +220,6 @@ const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: false, }; -export function futureFlagDefault(flag: string): boolean { +export function futureFlagDefault(flag: string): boolean | undefined { return FUTURE_FLAGS_DEFAULTS[flag]; } diff --git a/packages/@aws-cdk/cx-api/test/features.test.ts b/packages/@aws-cdk/cx-api/test/features.test.ts index 2aaa774b7b1c5..afc9c0838d7da 100644 --- a/packages/@aws-cdk/cx-api/test/features.test.ts +++ b/packages/@aws-cdk/cx-api/test/features.test.ts @@ -7,6 +7,10 @@ test('all future flags have defaults configured', () => { }); }); +test('futureFlagDefault returns undefined if non existent flag was given', () => { + expect(feats.futureFlagDefault('non-existent-flag')).toEqual(undefined); +}); + testLegacyBehavior('FUTURE_FLAGS_EXPIRED must be empty in CDKv1', Object, () => { expect(feats.FUTURE_FLAGS_EXPIRED.length).toEqual(0); }); From 354686b189377dd1daae7ba616e8fb62488d9855 Mon Sep 17 00:00:00 2001 From: "Michael R. Torres" <6692889+micrictor@users.noreply.github.com> Date: Wed, 27 Oct 2021 12:40:55 -0700 Subject: [PATCH 05/13] fix(custom-resources): invalid service name leads to unhelpful error message (#16718) fix(custom-resources): improve AwsSdkCall service error Makes the error that occurs when an invalid service name is supplied more explicit. Closes #7312 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/aws-custom-resource/runtime/index.ts | 3 ++ .../aws-custom-resource-provider.test.ts | 33 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/runtime/index.ts b/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/runtime/index.ts index a805fc8c2bf4d..e88b441637cfc 100644 --- a/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/runtime/index.ts +++ b/packages/@aws-cdk/custom-resources/lib/aws-custom-resource/runtime/index.ts @@ -176,6 +176,9 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent } + if (!Object.prototype.hasOwnProperty.call(AWS, call.service)) { + throw Error(`Service ${call.service} does not exist in AWS SDK version ${AWS.VERSION}.`); + } const awsService = new (AWS as any)[call.service]({ apiVersion: call.apiVersion, region: call.region, diff --git a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource-provider.test.ts b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource-provider.test.ts index 8a4786a138468..aa8a9589d1fdb 100644 --- a/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource-provider.test.ts +++ b/packages/@aws-cdk/custom-resources/test/aws-custom-resource/aws-custom-resource-provider.test.ts @@ -467,3 +467,36 @@ test('installs the latest SDK', async () => { // clean up aws-sdk install await fs.remove(tmpPath); }); + +test('invalid service name throws explicit error', async () => { + const publishFake = sinon.fake.resolves({}); + + AWS.mock('SNS', 'publish', publishFake); + + const event: AWSLambda.CloudFormationCustomResourceCreateEvent = { + ...eventCommon, + RequestType: 'Create', + ResourceProperties: { + ServiceToken: 'token', + Create: JSON.stringify({ + service: 'thisisnotarealservice', + action: 'publish', + parameters: { + Message: 'message', + TopicArn: 'topic', + }, + physicalResourceId: PhysicalResourceId.of('id'), + } as AwsSdkCall), + }, + }; + + const request = createRequest(body => + body.Status === 'FAILED' && + body.Reason!.startsWith('Service thisisnotarealservice does not exist'), + ); + + await handler(event, {} as AWSLambda.Context); + + expect(request.isDone()).toBeTruthy(); +}); + From 322cf10ef3257b9d20d898882a14de91110a0033 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Wed, 27 Oct 2021 22:32:54 +0200 Subject: [PATCH 06/13] feat(cli): deployment progress shows stack name (#16604) Allows to filter logs based on stack name, gives more context when looking at a log line in a log file. Useful in CI when multiple stacks are deployed in a run. (similar to lerna adding the package name) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../cloudformation/stack-activity-monitor.ts | 5 ++- .../test/api/stack-activity-monitor.test.ts | 42 +++++++++---------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts index 73075a41fee27..e956e63e3704c 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts @@ -523,8 +523,9 @@ export class HistoryActivityPrinter extends ActivityPrinterBase { this.stream.write( util.format( - ' %s%s | %s | %s | %s %s%s%s\n', - (progress !== false ? ` ${this.progress()} | ` : ''), + '%s | %s%s | %s | %s | %s %s%s%s\n', + e.StackName, + (progress !== false ? `${this.progress()} | ` : ''), new Date(e.Timestamp).toLocaleTimeString(), color(padRight(STATUS_WIDTH, (e.ResourceStatus || '').substr(0, STATUS_WIDTH))), // pad left and trim padRight(this.props.resourceTypeColumnWidth, e.ResourceType || ''), diff --git a/packages/aws-cdk/test/api/stack-activity-monitor.test.ts b/packages/aws-cdk/test/api/stack-activity-monitor.test.ts index c76ddda1ceb00..b793acda8b68b 100644 --- a/packages/aws-cdk/test/api/stack-activity-monitor.test.ts +++ b/packages/aws-cdk/test/api/stack-activity-monitor.test.ts @@ -27,12 +27,12 @@ test('prints 0/4 progress report, when addActivity is called with an "IN_PROGRES ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); }); - expect(output[0].trim()).toStrictEqual(`0/4 | ${HUMAN_TIME} | ${reset('IN_PROGRESS ')} | AWS::CloudFormation::Stack | ${reset(bold('stack1'))}`); + expect(output[0].trim()).toStrictEqual(`stack-name | 0/4 | ${HUMAN_TIME} | ${reset('IN_PROGRESS ')} | AWS::CloudFormation::Stack | ${reset(bold('stack1'))}`); }); test('prints 1/4 progress report, when addActivity is called with an "UPDATE_COMPLETE" ResourceStatus', () => { @@ -51,12 +51,12 @@ test('prints 1/4 progress report, when addActivity is called with an "UPDATE_COM ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); }); - expect(output[0].trim()).toStrictEqual(`1/4 | ${HUMAN_TIME} | ${green('UPDATE_COMPLETE ')} | AWS::CloudFormation::Stack | ${green(bold('stack1'))}`); + expect(output[0].trim()).toStrictEqual(`stack-name | 1/4 | ${HUMAN_TIME} | ${green('UPDATE_COMPLETE ')} | AWS::CloudFormation::Stack | ${green(bold('stack1'))}`); }); test('prints 1/4 progress report, when addActivity is called with an "UPDATE_COMPLETE_CLEAN_IN_PROGRESS" ResourceStatus', () => { @@ -75,12 +75,12 @@ test('prints 1/4 progress report, when addActivity is called with an "UPDATE_COM ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); }); - expect(output[0].trim()).toStrictEqual(`1/4 | ${HUMAN_TIME} | ${green('UPDATE_COMPLETE_CLEA')} | AWS::CloudFormation::Stack | ${green(bold('stack1'))}`); + expect(output[0].trim()).toStrictEqual(`stack-name | 1/4 | ${HUMAN_TIME} | ${green('UPDATE_COMPLETE_CLEA')} | AWS::CloudFormation::Stack | ${green(bold('stack1'))}`); }); @@ -100,12 +100,12 @@ test('prints 1/4 progress report, when addActivity is called with an "ROLLBACK_C ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); }); - expect(output[0].trim()).toStrictEqual(`1/4 | ${HUMAN_TIME} | ${yellow('ROLLBACK_COMPLETE_CL')} | AWS::CloudFormation::Stack | ${yellow(bold('stack1'))}`); + expect(output[0].trim()).toStrictEqual(`stack-name | 1/4 | ${HUMAN_TIME} | ${yellow('ROLLBACK_COMPLETE_CL')} | AWS::CloudFormation::Stack | ${yellow(bold('stack1'))}`); }); test('prints 0/4 progress report, when addActivity is called with an "UPDATE_FAILED" ResourceStatus', () => { @@ -124,12 +124,12 @@ test('prints 0/4 progress report, when addActivity is called with an "UPDATE_FAI ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); }); - expect(output[0].trim()).toStrictEqual(`0/4 | ${HUMAN_TIME} | ${red('UPDATE_FAILED ')} | AWS::CloudFormation::Stack | ${red(bold('stack1'))}`); + expect(output[0].trim()).toStrictEqual(`stack-name | 0/4 | ${HUMAN_TIME} | ${red('UPDATE_FAILED ')} | AWS::CloudFormation::Stack | ${red(bold('stack1'))}`); }); @@ -149,7 +149,7 @@ test('does not print "Failed Resources:" list, when all deployments are successf ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); historyActivityPrinter.addActivity({ @@ -160,7 +160,7 @@ test('does not print "Failed Resources:" list, when all deployments are successf ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); historyActivityPrinter.addActivity({ @@ -171,16 +171,16 @@ test('does not print "Failed Resources:" list, when all deployments are successf ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); historyActivityPrinter.stop(); }); expect(output.length).toStrictEqual(3); - expect(output[0].trim()).toStrictEqual(`0/2 | ${HUMAN_TIME} | ${reset('IN_PROGRESS ')} | AWS::CloudFormation::Stack | ${reset(bold('stack1'))}`); - expect(output[1].trim()).toStrictEqual(`1/2 | ${HUMAN_TIME} | ${green('UPDATE_COMPLETE ')} | AWS::CloudFormation::Stack | ${green(bold('stack1'))}`); - expect(output[2].trim()).toStrictEqual(`2/2 | ${HUMAN_TIME} | ${green('UPDATE_COMPLETE ')} | AWS::CloudFormation::Stack | ${green(bold('stack2'))}`); + expect(output[0].trim()).toStrictEqual(`stack-name | 0/2 | ${HUMAN_TIME} | ${reset('IN_PROGRESS ')} | AWS::CloudFormation::Stack | ${reset(bold('stack1'))}`); + expect(output[1].trim()).toStrictEqual(`stack-name | 1/2 | ${HUMAN_TIME} | ${green('UPDATE_COMPLETE ')} | AWS::CloudFormation::Stack | ${green(bold('stack1'))}`); + expect(output[2].trim()).toStrictEqual(`stack-name | 2/2 | ${HUMAN_TIME} | ${green('UPDATE_COMPLETE ')} | AWS::CloudFormation::Stack | ${green(bold('stack2'))}`); }); test('prints "Failed Resources:" list, when at least one deployment fails', () => { @@ -199,7 +199,7 @@ test('prints "Failed Resources:" list, when at least one deployment fails', () = ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); historyActivityPrinter.addActivity({ @@ -210,15 +210,15 @@ test('prints "Failed Resources:" list, when at least one deployment fails', () = ResourceType: 'AWS::CloudFormation::Stack', StackId: '', EventId: '', - StackName: '', + StackName: 'stack-name', }, }); historyActivityPrinter.stop(); }); expect(output.length).toStrictEqual(4); - expect(output[0].trim()).toStrictEqual(`0/2 | ${HUMAN_TIME} | ${reset('IN_PROGRESS ')} | AWS::CloudFormation::Stack | ${reset(bold('stack1'))}`); - expect(output[1].trim()).toStrictEqual(`0/2 | ${HUMAN_TIME} | ${red('UPDATE_FAILED ')} | AWS::CloudFormation::Stack | ${red(bold('stack1'))}`); + expect(output[0].trim()).toStrictEqual(`stack-name | 0/2 | ${HUMAN_TIME} | ${reset('IN_PROGRESS ')} | AWS::CloudFormation::Stack | ${reset(bold('stack1'))}`); + expect(output[1].trim()).toStrictEqual(`stack-name | 0/2 | ${HUMAN_TIME} | ${red('UPDATE_FAILED ')} | AWS::CloudFormation::Stack | ${red(bold('stack1'))}`); expect(output[2].trim()).toStrictEqual('Failed resources:'); - expect(output[3].trim()).toStrictEqual(`${HUMAN_TIME} | ${red('UPDATE_FAILED ')} | AWS::CloudFormation::Stack | ${red(bold('stack1'))}`); + expect(output[3].trim()).toStrictEqual(`stack-name | ${HUMAN_TIME} | ${red('UPDATE_FAILED ')} | AWS::CloudFormation::Stack | ${red(bold('stack1'))}`); }); From 3cfe8a2df9edfb3133e470eb8f2274efcc2adda1 Mon Sep 17 00:00:00 2001 From: vincent-turato <39069200+vincent-turato@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:24:25 -0700 Subject: [PATCH 07/13] feat(cloudtrail): selector for management event exclusions (#16546) Closes: #16273 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts | 24 ++++++++ .../aws-cloudtrail/test/cloudtrail.test.ts | 55 ++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts b/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts index 245c60600c08e..12cf079c5279e 100644 --- a/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts +++ b/packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts @@ -334,6 +334,7 @@ export class Trail extends Resource { values: dataResourceValues, }], includeManagementEvents: options.includeManagementEvents, + excludeManagementEventSources: options.excludeManagementEventSources, readWriteType: options.readWriteType, }); } @@ -424,6 +425,28 @@ export interface AddEventSelectorOptions { * @default true */ readonly includeManagementEvents?: boolean; + + /** + * An optional list of service event sources from which you do not want management events to be logged on your trail. + * + * @default [] + */ + readonly excludeManagementEventSources?: ManagementEventSources[]; +} + +/** + * Types of management event sources that can be excluded + */ +export enum ManagementEventSources { + /** + * AWS Key Management Service (AWS KMS) events + */ + KMS = 'kms.amazonaws.com', + + /** + * Data API events + */ + RDS_DATA_API = 'rdsdata.amazonaws.com', } /** @@ -457,6 +480,7 @@ export enum DataResourceType { interface EventSelector { readonly includeManagementEvents?: boolean; + readonly excludeManagementEventSources?: string[]; readonly readWriteType?: ReadWriteType; readonly dataResources?: EventSelectorData[]; } diff --git a/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts b/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts index 9e17345368785..c00f01d43acc4 100644 --- a/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts +++ b/packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts @@ -7,7 +7,7 @@ import { LogGroup, RetentionDays } from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; import { Stack } from '@aws-cdk/core'; -import { ReadWriteType, Trail } from '../lib'; +import { ManagementEventSources, ReadWriteType, Trail } from '../lib'; const ExpectedBucketPolicyProperties = { PolicyDocument: { @@ -446,6 +446,59 @@ describe('cloudtrail', () => { }); }); + test('exclude management events', () => { + const stack = getTestStack(); + const bucket = new s3.Bucket(stack, 'testBucket', { bucketName: 'test-bucket' }); + const cloudTrail = new Trail(stack, 'MyAmazingCloudTrail'); + cloudTrail.addS3EventSelector([{ bucket }], { + excludeManagementEventSources: [ + ManagementEventSources.KMS, + ManagementEventSources.RDS_DATA_API, + ], + }); + cloudTrail.addS3EventSelector([{ bucket }], { + excludeManagementEventSources: [], + }); + + expect(stack).toHaveResourceLike('AWS::CloudTrail::Trail', { + EventSelectors: [ + { + DataResources: [{ + Type: 'AWS::S3::Object', + Values: [{ + 'Fn::Join': [ + '', + [ + { 'Fn::GetAtt': ['testBucketDF4D7D1A', 'Arn'] }, + '/', + ], + ], + }], + }], + ExcludeManagementEventSources: [ + 'kms.amazonaws.com', + 'rdsdata.amazonaws.com', + ], + }, + { + DataResources: [{ + Type: 'AWS::S3::Object', + Values: [{ + 'Fn::Join': [ + '', + [ + { 'Fn::GetAtt': ['testBucketDF4D7D1A', 'Arn'] }, + '/', + ], + ], + }], + }], + ExcludeManagementEventSources: [], + }, + ], + }); + }); + test('for Lambda function data event', () => { const stack = getTestStack(); const lambdaFunction = new lambda.Function(stack, 'LambdaFunction', { From dbb3f25904403bfc020a081e94270f5c16a7606f Mon Sep 17 00:00:00 2001 From: Alban Esc Date: Wed, 27 Oct 2021 15:16:33 -0700 Subject: [PATCH 08/13] feat(events): DLQ support for EventBus target (#16383) Closes #15954. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-events-targets/README.md | 22 +++++- .../aws-events-targets/lib/event-bus.ts | 35 ++++++--- .../test/event-bus/event-rule-target.test.ts | 78 ++++++++++++++++++- .../event-bus/integ.event-bus.expected.json | 54 ++++++++++++- .../test/event-bus/integ.event-bus.ts | 7 ++ 5 files changed, 184 insertions(+), 12 deletions(-) diff --git a/packages/@aws-cdk/aws-events-targets/README.md b/packages/@aws-cdk/aws-events-targets/README.md index 76d25eab83dd3..1282cee012c5e 100644 --- a/packages/@aws-cdk/aws-events-targets/README.md +++ b/packages/@aws-cdk/aws-events-targets/README.md @@ -28,7 +28,7 @@ Currently supported are: * Put a record to a Kinesis stream * [Log an event into a LogGroup](#log-an-event-into-a-loggroup) * Put a record to a Kinesis Data Firehose stream -* Put an event on an EventBridge bus +* [Put an event on an EventBridge bus](#put-an-event-on-an-eventbridge-bus) See the README of the `@aws-cdk/aws-events` library for more information on EventBridge. @@ -266,3 +266,23 @@ rule.addTarget( } ), ) ``` + +## Put an event on an EventBridge bus + +Use the `EventBus` target to route event to a different EventBus. + +The code snippet below creates the scheduled event rule that route events to an imported event bus. + +```ts +const rule = new events.Rule(this, 'Rule', { + schedule: events.Schedule.expression('rate(1 minute)'), +}); + +rule.addTarget(new targets.EventBus( + events.EventBus.fromEventBusArn( + this, + 'External', + `arn:aws:events:eu-west-1:999999999999:event-bus/test-bus`, + ), +)); +``` diff --git a/packages/@aws-cdk/aws-events-targets/lib/event-bus.ts b/packages/@aws-cdk/aws-events-targets/lib/event-bus.ts index 8237b8cdd7993..7026273ef5330 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/event-bus.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/event-bus.ts @@ -1,9 +1,12 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; -import { singletonEventRole } from './util'; +import * as sqs from '@aws-cdk/aws-sqs'; +import { singletonEventRole, addToDeadLetterQueueResourcePolicy } from './util'; /** * Configuration properties of an Event Bus event + * + * Cannot extend TargetBaseProps. Retry policy is not supported for Event bus targets. */ export interface EventBusProps { /** @@ -12,25 +15,39 @@ export interface EventBusProps { * @default a new role is created. */ readonly role?: iam.IRole; + + /** + * The SQS queue to be used as deadLetterQueue. + * Check out the [considerations for using a dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html#dlq-considerations). + * + * The events not successfully delivered are automatically retried for a specified period of time, + * depending on the retry policy of the target. + * If an event is not delivered before all retry attempts are exhausted, it will be sent to the dead letter queue. + * + * @default - no dead-letter queue + */ + readonly deadLetterQueue?: sqs.IQueue; } /** * Notify an existing Event Bus of an event */ export class EventBus implements events.IRuleTarget { - private readonly role?: iam.IRole; - - constructor(private readonly eventBus: events.IEventBus, props: EventBusProps = {}) { - this.role = props.role; - } + constructor(private readonly eventBus: events.IEventBus, private readonly props: EventBusProps = {}) { } bind(rule: events.IRule, _id?: string): events.RuleTargetConfig { - if (this.role) { - this.role.addToPrincipalPolicy(this.putEventStatement()); + if (this.props.role) { + this.props.role.addToPrincipalPolicy(this.putEventStatement()); } - const role = this.role ?? singletonEventRole(rule, [this.putEventStatement()]); + const role = this.props.role ?? singletonEventRole(rule, [this.putEventStatement()]); + + if (this.props.deadLetterQueue) { + addToDeadLetterQueueResourcePolicy(rule, this.props.deadLetterQueue); + } + return { arn: this.eventBus.eventBusArn, + deadLetterConfig: this.props.deadLetterQueue ? { arn: this.props.deadLetterQueue?.queueArn } : undefined, role, }; } diff --git a/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts b/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts index 8d188f1550e8b..a6552a10d7a57 100644 --- a/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/event-bus/event-rule-target.test.ts @@ -1,6 +1,7 @@ import '@aws-cdk/assert-internal/jest'; import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; +import * as sqs from '@aws-cdk/aws-sqs'; import { Stack } from '@aws-cdk/core'; import * as targets from '../../lib'; @@ -90,4 +91,79 @@ test('with supplied role', () => { Ref: 'Role1ABCC5F0', }], }); -}); \ No newline at end of file +}); + +test('with a Dead Letter Queue specified', () => { + const stack = new Stack(); + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); + const queue = new sqs.Queue(stack, 'Queue'); + + rule.addTarget(new targets.EventBus( + events.EventBus.fromEventBusArn( + stack, + 'External', + 'arn:aws:events:us-east-1:123456789012:default', + ), + { deadLetterQueue: queue }, + )); + + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [{ + Arn: 'arn:aws:events:us-east-1:123456789012:default', + Id: 'Target0', + RoleArn: { + 'Fn::GetAtt': [ + 'RuleEventsRoleC51A4248', + 'Arn', + ], + }, + DeadLetterConfig: { + Arn: { + 'Fn::GetAtt': [ + 'Queue4A7E3555', + 'Arn', + ], + }, + }, + }], + }); + + expect(stack).toHaveResource('AWS::SQS::QueuePolicy', { + PolicyDocument: { + Statement: [ + { + Action: 'sqs:SendMessage', + Condition: { + ArnEquals: { + 'aws:SourceArn': { + 'Fn::GetAtt': [ + 'Rule4C995B7F', + 'Arn', + ], + }, + }, + }, + Effect: 'Allow', + Principal: { + Service: 'events.amazonaws.com', + }, + Resource: { + 'Fn::GetAtt': [ + 'Queue4A7E3555', + 'Arn', + ], + }, + Sid: 'AllowEventRuleRule', + }, + ], + Version: '2012-10-17', + }, + Queues: [ + { + Ref: 'Queue4A7E3555', + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-events-targets/test/event-bus/integ.event-bus.expected.json b/packages/@aws-cdk/aws-events-targets/test/event-bus/integ.event-bus.expected.json index 632ddf1767598..a10603f0b03b5 100644 --- a/packages/@aws-cdk/aws-events-targets/test/event-bus/integ.event-bus.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/event-bus/integ.event-bus.expected.json @@ -19,6 +19,14 @@ ] ] }, + "DeadLetterConfig": { + "Arn": { + "Fn::GetAtt": [ + "Queue4A7E3555", + "Arn" + ] + } + }, "Id": "Target0", "RoleArn": { "Fn::GetAtt": [ @@ -78,6 +86,50 @@ } ] } + }, + "Queue4A7E3555": { + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "QueuePolicy25439813": { + "Type": "AWS::SQS::QueuePolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "Rule4C995B7F", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + }, + "Resource": { + "Fn::GetAtt": [ + "Queue4A7E3555", + "Arn" + ] + }, + "Sid": "AllowEventRuleeventsourcestackRuleFCA41174" + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "Queue4A7E3555" + } + ] + } } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/event-bus/integ.event-bus.ts b/packages/@aws-cdk/aws-events-targets/test/event-bus/integ.event-bus.ts index c0ec2ea421b85..5a102ea3cba6c 100644 --- a/packages/@aws-cdk/aws-events-targets/test/event-bus/integ.event-bus.ts +++ b/packages/@aws-cdk/aws-events-targets/test/event-bus/integ.event-bus.ts @@ -1,5 +1,6 @@ /// !cdk-integ pragma:ignore-assets import * as events from '@aws-cdk/aws-events'; +import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import * as targets from '../../lib'; @@ -12,12 +13,18 @@ class EventSourceStack extends cdk.Stack { const rule = new events.Rule(this, 'Rule', { schedule: events.Schedule.expression('rate(1 minute)'), }); + + const queue = new sqs.Queue(this, 'Queue'); + rule.addTarget(new targets.EventBus( events.EventBus.fromEventBusArn( this, 'External', `arn:aws:events:${this.region}:999999999999:event-bus/test-bus`, ), + { + deadLetterQueue: queue, + }, )); } } From 5831456465fa44af96a268de56db0e3a8d3c2ea6 Mon Sep 17 00:00:00 2001 From: Julian Michel Date: Thu, 28 Oct 2021 01:09:43 +0200 Subject: [PATCH 09/13] fix(core): SecretValue.secretsManager fails for tokenized secret-id (#16230) `SecretValue.secretsManager` fails if a token is used for `secret-id`. This is caused by a validation which should be skipped for tokenized values. Solved by skipping the validation if token is unresolved. Fixes #16166. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/core/lib/secret-value.ts | 3 +- .../@aws-cdk/core/test/secret-value.test.ts | 47 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/core/lib/secret-value.ts b/packages/@aws-cdk/core/lib/secret-value.ts index 2cd1b772f3207..b57b704bd9ed6 100644 --- a/packages/@aws-cdk/core/lib/secret-value.ts +++ b/packages/@aws-cdk/core/lib/secret-value.ts @@ -1,6 +1,7 @@ import { CfnDynamicReference, CfnDynamicReferenceService } from './cfn-dynamic-reference'; import { CfnParameter } from './cfn-parameter'; import { Intrinsic } from './private/intrinsic'; +import { Token } from './token'; /** * Work with secret values in the CDK @@ -39,7 +40,7 @@ export class SecretValue extends Intrinsic { throw new Error('secretId cannot be empty'); } - if (!secretId.startsWith('arn:') && secretId.includes(':')) { + if (!Token.isUnresolved(secretId) && !secretId.startsWith('arn:') && secretId.includes(':')) { throw new Error(`secret id "${secretId}" is not an ARN but contains ":"`); } diff --git a/packages/@aws-cdk/core/test/secret-value.test.ts b/packages/@aws-cdk/core/test/secret-value.test.ts index a32702b98771d..2efcdffbe808d 100644 --- a/packages/@aws-cdk/core/test/secret-value.test.ts +++ b/packages/@aws-cdk/core/test/secret-value.test.ts @@ -1,4 +1,4 @@ -import { CfnDynamicReference, CfnDynamicReferenceService, CfnParameter, SecretValue, Stack } from '../lib'; +import { CfnDynamicReference, CfnDynamicReferenceService, CfnParameter, SecretValue, Stack, Token } from '../lib'; describe('secret value', () => { test('plainText', () => { @@ -28,6 +28,30 @@ describe('secret value', () => { }); + test('secretsManager with secret-id from token', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const v = SecretValue.secretsManager(Token.asString({ Ref: 'secret-id' }), { + jsonField: 'json-key', + versionStage: 'version-stage', + }); + + // THEN + expect(stack.resolve(v)).toEqual({ + 'Fn::Join': [ + '', + [ + '{{resolve:secretsmanager:', + { Ref: 'secret-id' }, + ':SecretString:json-key:version-stage:}}', + ], + ], + }); + + }); + test('secretsManager with defaults', () => { // GIVEN const stack = new Stack(); @@ -40,6 +64,27 @@ describe('secret value', () => { }); + test('secretsManager with defaults, secret-id from token', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const v = SecretValue.secretsManager(Token.asString({ Ref: 'secret-id' })); + + // THEN + expect(stack.resolve(v)).toEqual({ + 'Fn::Join': [ + '', + [ + '{{resolve:secretsmanager:', + { Ref: 'secret-id' }, + ':SecretString:::}}', + ], + ], + }); + + }); + test('secretsManager with an empty ID', () => { expect(() => SecretValue.secretsManager('')).toThrow(/secretId cannot be empty/); From e55301b635374a87822f78870981a9e06e13d99e Mon Sep 17 00:00:00 2001 From: Anurag Mohapatra Date: Thu, 28 Oct 2021 11:03:33 +1100 Subject: [PATCH 10/13] fix(cli): downgrade bootstrap stack error message needs a hint for new-style synthesis (#16237) Fix to the bootstrap error message on the version comparison to provide to peek at solution so as to warn users about new style stack synthesis not being enabled automatically in the cdk.json as the potential root cause Fixes https://github.com/aws/aws-cdk/issues/16009 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts b/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts index 4d66e59268dcc..49f97e71332c3 100644 --- a/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts +++ b/packages/aws-cdk/lib/api/bootstrap/deploy-bootstrap.ts @@ -65,7 +65,7 @@ export class BootstrapStack { const newVersion = bootstrapVersionFromTemplate(template); if (this.currentToolkitInfo.found && newVersion < this.currentToolkitInfo.version && !options.force) { - throw new Error(`Not downgrading existing bootstrap stack from version '${this.currentToolkitInfo.version}' to version '${newVersion}'. Use --force to force.`); + throw new Error(`Not downgrading existing bootstrap stack from version '${this.currentToolkitInfo.version}' to version '${newVersion}'. Use --force to force or set the '@aws-cdk/core:newStyleStackSynthesis' feature flag in cdk.json to use the latest bootstrap version.`); } const outdir = await fs.mkdtemp(path.join(os.tmpdir(), 'cdk-bootstrap')); @@ -114,4 +114,4 @@ export function bootstrapVersionFromTemplate(template: any): number { } } return 0; -} \ No newline at end of file +} From a6aaa64bf9779b984f20d18881b4f6e510ac091a Mon Sep 17 00:00:00 2001 From: James Lakin Date: Thu, 28 Oct 2021 01:56:20 +0100 Subject: [PATCH 11/13] fix(logs): Apply tags to log retention Lambda (#17029) This hopefully fixes #15032 by implementing the `ITaggable` interface on the custom construct and then applying discovered tags to the underlying `CfnResource`. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-logs/lib/log-retention.ts | 5 +- .../aws-logs/test/log-retention.test.ts | 19 ++++++++ packages/@aws-cdk/core/lib/tag-manager.ts | 46 ++++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-logs/lib/log-retention.ts b/packages/@aws-cdk/aws-logs/lib/log-retention.ts index f3054cf910f1c..fe4e3e3cff7af 100644 --- a/packages/@aws-cdk/aws-logs/lib/log-retention.ts +++ b/packages/@aws-cdk/aws-logs/lib/log-retention.ts @@ -128,9 +128,11 @@ export class LogRetention extends CoreConstruct { /** * Private provider Lambda function to support the log retention custom resource. */ -class LogRetentionFunction extends CoreConstruct { +class LogRetentionFunction extends CoreConstruct implements cdk.ITaggable { public readonly functionArn: cdk.Reference; + public readonly tags: cdk.TagManager = new cdk.TagManager(cdk.TagType.KEY_VALUE, 'AWS::Lambda::Function'); + constructor(scope: Construct, id: string, props: LogRetentionProps) { super(scope, id); @@ -164,6 +166,7 @@ class LogRetentionFunction extends CoreConstruct { S3Key: asset.s3ObjectKey, }, Role: role.roleArn, + Tags: this.tags.renderedTags, }, }); this.functionArn = resource.getAtt('Arn'); diff --git a/packages/@aws-cdk/aws-logs/test/log-retention.test.ts b/packages/@aws-cdk/aws-logs/test/log-retention.test.ts index 8f8ed85bb4d47..208031bc1744b 100644 --- a/packages/@aws-cdk/aws-logs/test/log-retention.test.ts +++ b/packages/@aws-cdk/aws-logs/test/log-retention.test.ts @@ -156,4 +156,23 @@ describe('log retention', () => { expect(logGroupArn.endsWith(':*')).toEqual(true); }); + + test('retention Lambda CfnResource receives propagated tags', () => { + const stack = new cdk.Stack(); + cdk.Tags.of(stack).add('test-key', 'test-value'); + new LogRetention(stack, 'MyLambda', { + logGroupName: 'group', + retention: RetentionDays.ONE_MONTH, + }); + + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { + Tags: [ + { + Key: 'test-key', + Value: 'test-value', + }, + ], + }); + + }); }); diff --git a/packages/@aws-cdk/core/lib/tag-manager.ts b/packages/@aws-cdk/core/lib/tag-manager.ts index cdc224500ef1b..8f4893d5036f0 100644 --- a/packages/@aws-cdk/core/lib/tag-manager.ts +++ b/packages/@aws-cdk/core/lib/tag-manager.ts @@ -1,5 +1,7 @@ import { TagType } from './cfn-resource'; import { CfnTag } from './cfn-tag'; +import { Lazy } from './lazy'; +import { IResolvable } from './resolvable'; interface Tag { key: string; @@ -172,7 +174,7 @@ class KeyValueFormatter implements ITagFormatter { Value: tag.value, }); }); - return tags; + return tags.length > 0 ? tags : undefined; } } @@ -228,7 +230,32 @@ export interface TagManagerOptions { } /** - * TagManager facilitates a common implementation of tagging for Constructs. + * TagManager facilitates a common implementation of tagging for Constructs + * + * Normally, you do not need to use this class, as the CloudFormation specification + * will indicate which resources are taggable. However, sometimes you will need this + * to make custom resources taggable. Used `tagManager.renderedTags` to obtain a + * value that will resolve to the tags at synthesis time. + * + * @example + * import * as cdk from '@aws-cdk/core'; + * + * class MyConstruct extends cdk.Resource implements cdk.ITaggable { + * public readonly tags = new cdk.TagManager(cdk.TagType.KEY_VALUE, 'Whatever::The::Type'); + * + * constructor(scope: cdk.Construct, id: string) { + * super(scope, id); + * + * new cdk.CfnResource(this, 'Resource', { + * type: 'Whatever::The::Type', + * properties: { + * // ... + * Tags: this.tags.renderedTags, + * }, + * }); + * } + * } + * */ export class TagManager { @@ -247,6 +274,14 @@ export class TagManager { */ public readonly tagPropertyName: string; + /** + * A lazy value that represents the rendered tags at synthesis time + * + * If you need to make a custom construct taggable, use the value of this + * property to pass to the `tags` property of the underlying construct. + */ + public readonly renderedTags: IResolvable; + private readonly tags = new Map(); private readonly priorities = new Map(); private readonly tagFormatter: ITagFormatter; @@ -260,6 +295,8 @@ export class TagManager { this._setTag(...this.tagFormatter.parseTags(tagStructure, this.initialTagPriority)); } this.tagPropertyName = options.tagPropertyName || 'tags'; + + this.renderedTags = Lazy.any({ produce: () => this.renderTags() }); } /** @@ -287,6 +324,11 @@ export class TagManager { /** * Renders tags into the proper format based on TagType + * + * This method will eagerly render the tags currently applied. In + * most cases, you should be using `tagManager.renderedTags` instead, + * which will return a `Lazy` value that will resolve to the correct + * tags at synthesis time. */ public renderTags(): any { return this.tagFormatter.formatTags(this.sortedTags); From 823c4d6700fdbba7f0defb2cf4daa1543738284b Mon Sep 17 00:00:00 2001 From: kaizen3031593 <36202692+kaizen3031593@users.noreply.github.com> Date: Wed, 27 Oct 2021 21:49:12 -0400 Subject: [PATCH 12/13] chore(lambda): make examples compile (#17188) ---- *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/README.md | 218 +++++++++--------- .../aws-lambda/rosetta/default.ts-fixture | 6 +- .../aws-lambda/rosetta/function.ts-fixture | 18 -- 3 files changed, 118 insertions(+), 124 deletions(-) delete mode 100644 packages/@aws-cdk/aws-lambda/rosetta/function.ts-fixture diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index dc97826d51135..bb42d0811994d 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -14,10 +14,10 @@ This construct library allows you to define AWS Lambda Functions. ```ts -const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); ``` @@ -62,8 +62,8 @@ The following `DockerImageFunction` construct uses a local folder with a Dockerfile as the asset that will be used as the function handler. ```ts -new DockerImageFunction(this, 'AssetFunction', { - code: DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-handler')), +new lambda.DockerImageFunction(this, 'AssetFunction', { + code: lambda.DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-handler')), }); ``` @@ -73,8 +73,8 @@ You can also specify an image that already exists in ECR as the function handler import * as ecr from '@aws-cdk/aws-ecr'; const repo = new ecr.Repository(this, 'Repository'); -new DockerImageFunction(this, 'ECRFunction', { - code: DockerImageCode.fromEcr(repo), +new lambda.DockerImageFunction(this, 'ECRFunction', { + code: lambda.DockerImageCode.fromEcr(repo), }); ``` @@ -90,13 +90,13 @@ The autogenerated Role is automatically given permissions to execute the Lambda function. To reference the autogenerated Role: ```ts -const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); -fn.role // the Role +const role = fn.role; // the Role ``` You can also provide your own IAM role. Provided IAM roles will not automatically @@ -104,15 +104,15 @@ be given permissions to execute the Lambda function. To provide a role and grant it appropriate permissions: ```ts -import * as iam from '@aws-cdk/aws-iam'; const myRole = new iam.Role(this, 'My Role', { assumedBy: new iam.ServicePrincipal('sns.amazonaws.com'), }); -const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, + +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), - role: myRole // user-provided role + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + role: myRole, // user-provided role }); myRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")); @@ -128,8 +128,8 @@ functions. You can also restrict permissions given to AWS services by providing a source account or ARN (representing the account and identifier of the resource that accesses the function or layer). -```ts fixture=function -import * as iam from '@aws-cdk/aws-iam'; +```ts +declare const fn: lambda.Function; const principal = new iam.ServicePrincipal('my-service'); fn.grantInvoke(principal); @@ -151,8 +151,8 @@ principal in question has conditions limiting the source account or ARN of the operation (see above), these conditions will be automatically added to the resource policy. -```ts fixture=function -import * as iam from '@aws-cdk/aws-iam'; +```ts +declare const fn: lambda.Function; const servicePrincipal = new iam.ServicePrincipal('my-service'); const sourceArn = 'arn:aws:s3:::my-bucket'; const sourceAccount = '111122223333'; @@ -193,8 +193,8 @@ The function version includes the following information: You could create a version to your lambda function using the `Version` construct. ```ts -const fn = new Function(this, 'MyFunction', ...); -const version = new Version(this, 'MyVersion', { +declare const fn: lambda.Function; +const version = new lambda.Version(this, 'MyVersion', { lambda: fn, }); ``` @@ -211,9 +211,12 @@ latest code. For instance - ```ts const codeVersion = "stringOrMethodToGetCodeVersion"; const fn = new lambda.Function(this, 'MyFunction', { - environment: { - 'CodeVersionString': codeVersion - } + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + environment: { + 'CodeVersionString': codeVersion, + }, }); ``` @@ -291,16 +294,14 @@ specify options for the current version through the `currentVersionOptions` property. ```ts -import * as cdk from '@aws-cdk/core'; - -const fn = new Function(this, 'MyFunction', { +const fn = new lambda.Function(this, 'MyFunction', { currentVersionOptions: { - removalPolicy: cdk.RemovalPolicy.RETAIN, // retain old versions - retryAttempts: 1 // async retry attempts + removalPolicy: RemovalPolicy.RETAIN, // retain old versions + retryAttempts: 1, // async retry attempts }, - runtime: Runtime.NODEJS_12_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); fn.currentVersion.addAlias('live'); @@ -318,11 +319,9 @@ By default, updating a layer creates a new layer version, and CloudFormation wil Alternatively, a removal policy can be used to retain the old version: ```ts -import * as cdk from '@aws-cdk/core'; - -new LayerVersion(this, 'MyLayer', { - removalPolicy: cdk.RemovalPolicy.RETAIN, - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), +new lambda.LayerVersion(this, 'MyLayer', { + removalPolicy: RemovalPolicy.RETAIN, + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); ``` @@ -336,18 +335,21 @@ for some workloads. A lambda function can be configured to be run on one of these platforms: ```ts -new Function(this, 'MyFunction', { - ... - architecture: Architecture.ARM_64, +new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + architecture: lambda.Architecture.ARM_64, }); ``` Similarly, lambda layer versions can also be tagged with architectures it is compatible with. ```ts -new LayerVersion(this, 'MyLayer', { - ... - compatibleArchitectures: [Architecture.X86_64, Architecture.ARM_64], +new lambda.LayerVersion(this, 'MyLayer', { + removalPolicy: RemovalPolicy.RETAIN, + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + compatibleArchitectures: [lambda.Architecture.X86_64, lambda.Architecture.ARM_64], }); ``` @@ -357,20 +359,24 @@ Lambda functions can be configured to use CloudWatch [Lambda Insights](https://d which provides low-level runtime metrics for a Lambda functions. ```ts -import * as lambda from '@aws-cdk/lambda'; - -new Function(this, 'MyFunction', { - insightsVersion: lambda.LambdaInsightsVersion.VERSION_1_0_98_0 -}) +new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + insightsVersion: lambda.LambdaInsightsVersion.VERSION_1_0_98_0, +}); ``` If the version of insights is not yet available in the CDK, you can also provide the ARN directly as so - ```ts const layerArn = 'arn:aws:lambda:us-east-1:580247275435:layer:LambdaInsightsExtension:14'; -new Function(this, 'MyFunction', { - insightsVersion: lambda.LambdaInsightsVersion.fromInsightVersionArn(layerArn) -}) +new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + insightsVersion: lambda.LambdaInsightsVersion.fromInsightVersionArn(layerArn), +}); ``` ## Event Rule Target @@ -378,9 +384,11 @@ new Function(this, 'MyFunction', { You can use an AWS Lambda function as a target for an Amazon CloudWatch event rule: -```ts fixture=function +```ts import * as events from '@aws-cdk/aws-events'; import * as targets from '@aws-cdk/aws-events-targets'; + +declare const fn: lambda.Function; const rule = new events.Rule(this, 'Schedule Rule', { schedule: events.Schedule.cron({ minute: '0', hour: '4' }), }); @@ -402,18 +410,22 @@ includes classes for the various event sources supported by AWS Lambda. For example, the following code adds an SQS queue as an event source for a function: -```ts fixture=function +```ts import * as eventsources from '@aws-cdk/aws-lambda-event-sources'; import * as sqs from '@aws-cdk/aws-sqs'; + +declare const fn: lambda.Function; const queue = new sqs.Queue(this, 'Queue'); fn.addEventSource(new eventsources.SqsEventSource(queue)); ``` The following code adds an S3 bucket notification as an event source: -```ts fixture=function +```ts import * as eventsources from '@aws-cdk/aws-lambda-event-sources'; import * as s3 from '@aws-cdk/aws-s3'; + +declare const fn: lambda.Function; const bucket = new s3.Bucket(this, 'Bucket'); fn.addEventSource(new eventsources.S3EventSource(bucket, { events: [ s3.EventType.OBJECT_CREATED, s3.EventType.OBJECT_REMOVED ], @@ -429,11 +441,11 @@ A dead-letter queue can be automatically created for a Lambda function by setting the `deadLetterQueueEnabled: true` configuration. ```ts -const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, - handler: 'index.handler', - code: Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), - deadLetterQueueEnabled: true +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), + deadLetterQueueEnabled: true, }); ``` @@ -443,11 +455,11 @@ It is also possible to provide a dead-letter queue instead of getting a new queu import * as sqs from '@aws-cdk/aws-sqs'; const dlq = new sqs.Queue(this, 'DLQ'); -const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, - handler: 'index.handler', - code: Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), - deadLetterQueue: dlq +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), + deadLetterQueue: dlq, }); ``` @@ -457,11 +469,11 @@ to learn more about AWS Lambdas and DLQs. ## Lambda with X-Ray Tracing ```ts -const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, - handler: 'index.handler', - code: Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), - tracing: Tracing.ACTIVE +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), + tracing: lambda.Tracing.ACTIVE, }); ``` @@ -474,13 +486,11 @@ The following code configures the lambda function with CodeGuru profiling. By de profiling group - ```ts -import * as lambda from '@aws-cdk/aws-lambda'; - -const fn = new Function(this, 'MyFunction', { - runtime: Runtime.PYTHON_3_6, - handler: 'index.handler', - code: Code.fromAsset('lambda-handler'), - profiling: true +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.PYTHON_3_6, + handler: 'index.handler', + code: lambda.Code.fromAsset('lambda-handler'), + profiling: true, }); ``` @@ -494,11 +504,11 @@ to learn more about AWS Lambda's Profiling support. ## Lambda with Reserved Concurrent Executions ```ts -const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, - handler: 'index.handler', - code: Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), - reservedConcurrentExecutions: 100 +const fn = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'), + reservedConcurrentExecutions: 100, }); ``` @@ -509,15 +519,17 @@ managing concurrency. You can use Application AutoScaling to automatically configure the provisioned concurrency for your functions. AutoScaling can be set to track utilization or be based on a schedule. To configure AutoScaling on a function alias: -```ts fixture=function +```ts import * as autoscaling from '@aws-cdk/aws-autoscaling'; -const alias = new Alias(this, 'Alias', { + +declare const fn: lambda.Function; +const alias = new lambda.Alias(this, 'Alias', { aliasName: 'prod', version: fn.latestVersion, }); // Create AutoScaling target -const as = alias.addAutoScaling({ maxCapacity: 50 }) +const as = alias.addAutoScaling({ maxCapacity: 50 }); // Configure Target Tracking as.scaleOnUtilization({ @@ -591,12 +603,12 @@ const accessPoint = fileSystem.addAccessPoint('AccessPoint', { }, }); -const fn = new Function(this, 'MyLambda', { +const fn = new lambda.Function(this, 'MyLambda', { // mount the access point to /mnt/msg in the lambda runtime environment - filesystem: FileSystem.fromEfsAccessPoint(accessPoint, '/mnt/msg'), - runtime: Runtime.NODEJS_12_X, + filesystem: lambda.FileSystem.fromEfsAccessPoint(accessPoint, '/mnt/msg'), + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), vpc, }); ``` @@ -626,17 +638,17 @@ Docker container is responsible for putting content at `/asset-output`. The cont Example with Python: ```ts -new Function(this, 'Function', { - code: Code.fromAsset(path.join(__dirname, 'my-python-handler'), { +new lambda.Function(this, 'Function', { + code: lambda.Code.fromAsset(path.join(__dirname, 'my-python-handler'), { bundling: { - image: Runtime.PYTHON_3_9.bundlingImage, + image: lambda.Runtime.PYTHON_3_9.bundlingImage, command: [ 'bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output' ], }, }), - runtime: Runtime.PYTHON_3_9, + runtime: lambda.Runtime.PYTHON_3_9, handler: 'index.handler', }); ``` @@ -647,12 +659,10 @@ Use `cdk.DockerImage.fromRegistry(image)` to use an existing image or `cdk.DockerImage.fromBuild(path)` to build a specific image: ```ts -import * as cdk from '@aws-cdk/core'; - -new Function(this, 'Function', { - code: Code.fromAsset('/path/to/handler', { +new lambda.Function(this, 'Function', { + code: lambda.Code.fromAsset('/path/to/handler', { bundling: { - image: cdk.DockerImage.fromBuild('/path/to/dir/with/DockerFile', { + image: DockerImage.fromBuild('/path/to/dir/with/DockerFile', { buildArgs: { ARG1: 'value1', }, @@ -660,7 +670,7 @@ new Function(this, 'Function', { command: ['my', 'cool', 'command'], }, }), - runtime: Runtime.PYTHON_3_9, + runtime: lambda.Runtime.PYTHON_3_9, handler: 'index.handler', }); ``` @@ -679,21 +689,21 @@ When enabled, AWS Lambda checks every code deployment and verifies that the code For more information, see [Configuring code signing for AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/configuration-codesigning.html). The following code configures a function with code signing. -```typescript +```ts import * as signer from '@aws-cdk/aws-signer'; const signingProfile = new signer.SigningProfile(this, 'SigningProfile', { - platform: signer.Platform.AWS_LAMBDA_SHA384_ECDSA + platform: signer.Platform.AWS_LAMBDA_SHA384_ECDSA, }); -const codeSigningConfig = new CodeSigningConfig(this, 'CodeSigningConfig', { +const codeSigningConfig = new lambda.CodeSigningConfig(this, 'CodeSigningConfig', { signingProfiles: [signingProfile], }); -new Function(this, 'Function', { +new lambda.Function(this, 'Function', { codeSigningConfig, - runtime: Runtime.NODEJS_12_X, + runtime: lambda.Runtime.NODEJS_12_X, handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), }); ``` diff --git a/packages/@aws-cdk/aws-lambda/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-lambda/rosetta/default.ts-fixture index 417454806bb9d..f473db8d31bd5 100644 --- a/packages/@aws-cdk/aws-lambda/rosetta/default.ts-fixture +++ b/packages/@aws-cdk/aws-lambda/rosetta/default.ts-fixture @@ -1,7 +1,9 @@ // Fixture with packages imported, but nothing else import * as path from 'path'; -import { Construct, Stack } from '@aws-cdk/core'; -import { Alias, Code, CodeSigningConfig, DockerImageCode, DockerImageFunction, FileSystem, Function, LayerVersion, Runtime, Tracing } from '@aws-cdk/aws-lambda'; +import { Construct } from 'constructs'; +import { DockerImage, RemovalPolicy, Stack } from '@aws-cdk/core'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as iam from '@aws-cdk/aws-iam'; class Fixture extends Stack { constructor(scope: Construct, id: string) { diff --git a/packages/@aws-cdk/aws-lambda/rosetta/function.ts-fixture b/packages/@aws-cdk/aws-lambda/rosetta/function.ts-fixture deleted file mode 100644 index 91eafe0abfcc0..0000000000000 --- a/packages/@aws-cdk/aws-lambda/rosetta/function.ts-fixture +++ /dev/null @@ -1,18 +0,0 @@ -// Fixture with function (`fn`) already created -import * as path from 'path'; -import { Construct, Stack } from '@aws-cdk/core'; -import { Alias, Code, Function, Runtime } from '@aws-cdk/aws-lambda'; - -class Fixture extends Stack { - constructor(scope: Construct, id: string) { - super(scope, id); - - const fn = new Function(this, 'MyFunction', { - runtime: Runtime.NODEJS_12_X, - handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'lambda-handler')), - }); - - /// here - } -} From 029eed9c8341545e090ec48ee97b47d25f4c3c56 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 28 Oct 2021 04:44:23 +0200 Subject: [PATCH 13/13] chore: upgrade to jsii 1.41 (#17190) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- package.json | 8 +- packages/awslint/package.json | 4 +- packages/decdk/package.json | 4 +- tools/@aws-cdk/cdk-build-tools/package.json | 6 +- yarn.lock | 162 ++++++++------------ 5 files changed, 74 insertions(+), 110 deletions(-) diff --git a/package.json b/package.json index 6115ddc36950c..7a521b7db98e1 100644 --- a/package.json +++ b/package.json @@ -20,10 +20,10 @@ "fs-extra": "^9.1.0", "graceful-fs": "^4.2.8", "jest-junit": "^12.3.0", - "jsii-diff": "^1.40.0", - "jsii-pacmak": "^1.40.0", - "jsii-reflect": "^1.40.0", - "jsii-rosetta": "^1.40.0", + "jsii-diff": "^1.41.0", + "jsii-pacmak": "^1.41.0", + "jsii-reflect": "^1.41.0", + "jsii-rosetta": "^1.41.0", "lerna": "^4.0.0", "patch-package": "^6.4.7", "standard-version": "^9.3.1", diff --git a/packages/awslint/package.json b/packages/awslint/package.json index 1bae6a09ba6cb..df07c732685ef 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -18,11 +18,11 @@ "awslint": "bin/awslint" }, "dependencies": { - "@jsii/spec": "^1.40.0", + "@jsii/spec": "^1.41.0", "camelcase": "^6.2.0", "colors": "^1.4.0", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.40.0", + "jsii-reflect": "^1.41.0", "yargs": "^16.2.0" }, "devDependencies": { diff --git a/packages/decdk/package.json b/packages/decdk/package.json index 6a0a0eb5c0baa..7ebd9cc3d632c 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -244,7 +244,7 @@ "@aws-cdk/region-info": "0.0.0", "constructs": "^3.3.69", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.40.0", + "jsii-reflect": "^1.41.0", "jsonschema": "^1.4.0", "yaml": "1.10.2", "yargs": "^16.2.0" @@ -255,7 +255,7 @@ "@types/yaml": "1.9.7", "@types/yargs": "^15.0.14", "jest": "^26.6.3", - "jsii": "^1.40.0" + "jsii": "^1.41.0" }, "keywords": [ "aws", diff --git a/tools/@aws-cdk/cdk-build-tools/package.json b/tools/@aws-cdk/cdk-build-tools/package.json index c8dfb507afc46..a99a32059c006 100644 --- a/tools/@aws-cdk/cdk-build-tools/package.json +++ b/tools/@aws-cdk/cdk-build-tools/package.json @@ -56,9 +56,9 @@ "fs-extra": "^9.1.0", "jest": "^27.3.1", "jest-junit": "^11.1.0", - "jsii": "^1.40.0", - "jsii-pacmak": "^1.40.0", - "jsii-reflect": "^1.40.0", + "jsii": "^1.41.0", + "jsii-pacmak": "^1.41.0", + "jsii-reflect": "^1.41.0", "markdownlint-cli": "^0.29.0", "nyc": "^15.1.0", "semver": "^7.3.5", diff --git a/yarn.lock b/yarn.lock index c63b92155ae6a..48ecde5d6ee28 100644 --- a/yarn.lock +++ b/yarn.lock @@ -760,10 +760,18 @@ chalk "^4.1.2" semver "^7.3.5" -"@jsii/spec@^1.40.0": - version "1.40.0" - resolved "https://registry.npmjs.org/@jsii/spec/-/spec-1.40.0.tgz#027dd2a9c2c0b49e5974ad6445728dde91569fe3" - integrity sha512-SJ9Kwz0C53bomYWb5PlESt6v8JmfgqqFjc1annNK+foHxcaUzs3trhKbBXgxhcoApE2pMnUIBj3DG9gLNmKdWw== +"@jsii/check-node@1.41.0": + version "1.41.0" + resolved "https://registry.npmjs.org/@jsii/check-node/-/check-node-1.41.0.tgz#17b6895e1fcc0b8bbb8fa81b52b17c47c9c47674" + integrity sha512-lV/vMK1HZQcUye2vXPu6XsmnTk7fEui0GnQsPAX1eLWfRMkxkRblT4VZ9DQTYjMno2HuVP4IH51fiFoICMmnkA== + dependencies: + chalk "^4.1.2" + semver "^7.3.5" + +"@jsii/spec@^1.41.0": + version "1.41.0" + resolved "https://registry.npmjs.org/@jsii/spec/-/spec-1.41.0.tgz#d504c8536139a97986b1ec63201d3575972e1e9c" + integrity sha512-sN7x6C0DGLngiO6SkrM/7gVaHyeja59bDZODZtBXIq8kBIC+GgAFS8P0s1e5FpU9mHHvvHq4rvzvcIbxw0nkXw== dependencies: jsonschema "^1.4.0" @@ -2250,11 +2258,6 @@ ansi-regex@^2.0.0: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -3078,11 +3081,6 @@ co@^4.6.0: resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - codemaker@^1.39.0: version "1.39.0" resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.39.0.tgz#d8103f4b587210b1d6aa073d62ffb510ac20bc42" @@ -3092,10 +3090,10 @@ codemaker@^1.39.0: decamelize "^5.0.1" fs-extra "^9.1.0" -codemaker@^1.40.0: - version "1.40.0" - resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.40.0.tgz#80ed75a433fb08976c602b9080dc7fffbb13dbb9" - integrity sha512-X0dMlXILO5r9/YhNAbiLl9kNIfhATfGS8nAT7xC09zREipANnCEbjZuF8jtFGzrD942/k5QNROmqRtqRaZJ1QQ== +codemaker@^1.41.0: + version "1.41.0" + resolved "https://registry.npmjs.org/codemaker/-/codemaker-1.41.0.tgz#814edff6ffd241727794e76f81c5f9e4df135162" + integrity sha512-Iow0udcpshcVmztwSSJDTRhJxTbH0nXU3pxf7iF0gv6+BWC5Nd2aWQ2W5rHECySQPIvmWn4KEpV/SvXgvfl0aA== dependencies: camelcase "^6.2.0" decamelize "^5.0.1" @@ -5536,18 +5534,6 @@ is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -6706,70 +6692,72 @@ jsesc@^2.5.1: resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsii-diff@^1.40.0: - version "1.40.0" - resolved "https://registry.npmjs.org/jsii-diff/-/jsii-diff-1.40.0.tgz#97668273bc6c7f8ea6c6c27ebd8d70d433e1208d" - integrity sha512-Q0ctTmPE3wZ03CP++MxjPMBV3ynonDHq1gsd5mFUk9DW+cTyKb78KUkyjhgQnuiehXLRDQtoTlWJkH9C5xhEnQ== +jsii-diff@^1.41.0: + version "1.41.0" + resolved "https://registry.npmjs.org/jsii-diff/-/jsii-diff-1.41.0.tgz#ef88aa98081e4bb41f13d24074fce9bee1574d24" + integrity sha512-LTfqGh0f0fUuWu8DBkEUgl0fteIBfzyEiExcqLBXbztg/8JRbt3DYUr63hHULJj4O/rnRTaaYNH7oT1sg4gpSQ== dependencies: - "@jsii/check-node" "1.40.0" - "@jsii/spec" "^1.40.0" + "@jsii/check-node" "1.41.0" + "@jsii/spec" "^1.41.0" fs-extra "^9.1.0" - jsii-reflect "^1.40.0" + jsii-reflect "^1.41.0" log4js "^6.3.0" typescript "~3.9.10" yargs "^16.2.0" -jsii-pacmak@^1.40.0: - version "1.40.0" - resolved "https://registry.npmjs.org/jsii-pacmak/-/jsii-pacmak-1.40.0.tgz#5c0ecd5ff9c0917931bbe66773402dfe5517fbec" - integrity sha512-8IyvvWiD2eUpVhw0WXrYJILz+NSeNEwcWfQB+fUmn2gL8q27hlPZhHE7BVlr8+rb+EJVVLeHmpAMgA/SF9g/vQ== +jsii-pacmak@^1.41.0: + version "1.41.0" + resolved "https://registry.npmjs.org/jsii-pacmak/-/jsii-pacmak-1.41.0.tgz#b94575f4a7c658d3fbd1c5f30876ce53a22ed126" + integrity sha512-B3ohEObc2xSnWoawK0q4qVkxa9Dh4A+x1y9K31AAS5jGbhdjbdS/FfphlUbukIoSR0NBJLgJg9pT+h/PIlUqdA== dependencies: - "@jsii/check-node" "1.40.0" - "@jsii/spec" "^1.40.0" + "@jsii/check-node" "1.41.0" + "@jsii/spec" "^1.41.0" clone "^2.1.2" - codemaker "^1.40.0" + codemaker "^1.41.0" commonmark "^0.30.0" escape-string-regexp "^4.0.0" fs-extra "^9.1.0" - jsii-reflect "^1.40.0" - jsii-rosetta "^1.40.0" + jsii-reflect "^1.41.0" + jsii-rosetta "^1.41.0" semver "^7.3.5" spdx-license-list "^6.4.0" xmlbuilder "^15.1.1" yargs "^16.2.0" -jsii-reflect@^1.40.0: - version "1.40.0" - resolved "https://registry.npmjs.org/jsii-reflect/-/jsii-reflect-1.40.0.tgz#f8715f1506059d49294b32fe2c710753dd9545ba" - integrity sha512-/ccIjkRSfbHCl1MCfwWFaz2RjoAAiNH5teE95Qi11a4gbTu52WcOFIg3Y+8llzHmmLykr9jTDqBtgyzi9WI6dw== +jsii-reflect@^1.41.0: + version "1.41.0" + resolved "https://registry.npmjs.org/jsii-reflect/-/jsii-reflect-1.41.0.tgz#3c8fbcbbb7e2853b7c2a59384524ccbd2d9d832c" + integrity sha512-KQaAXQ38hyREs7IuBChZldSyvW1gezHRezGKGc6BZILwlIX330F3GIauJ2rJKJinh/Lo/DlMfd0k1mxdBz/W9A== dependencies: - "@jsii/check-node" "1.40.0" - "@jsii/spec" "^1.40.0" + "@jsii/check-node" "1.41.0" + "@jsii/spec" "^1.41.0" colors "^1.4.0" fs-extra "^9.1.0" - oo-ascii-tree "^1.40.0" + oo-ascii-tree "^1.41.0" yargs "^16.2.0" -jsii-rosetta@^1.40.0: - version "1.40.0" - resolved "https://registry.npmjs.org/jsii-rosetta/-/jsii-rosetta-1.40.0.tgz#eff34919ed9d4193ddb4a684f6108c82db3feb7c" - integrity sha512-Gb257CdUbHV8ZRFYflZy7F7alH5X49T+pX2133F7eaoMpRqc0V6jQsphaL4V+S/jK29XOfXtANmq55AvmwsWLQ== +jsii-rosetta@^1.41.0: + version "1.41.0" + resolved "https://registry.npmjs.org/jsii-rosetta/-/jsii-rosetta-1.41.0.tgz#ddf3f49738489d8330aa4eff96f0a9c8c811792d" + integrity sha512-wSjMqRBhjBKB8kx+gIXE7YXoiOlTFH/ugksHz2K4UwqriPmEHue8b7LkV3d/mD8xuhXWS6ekGAz67Gd1RSB7Sg== dependencies: - "@jsii/check-node" "1.40.0" - "@jsii/spec" "^1.40.0" + "@jsii/check-node" "1.41.0" + "@jsii/spec" "^1.41.0" "@xmldom/xmldom" "^0.7.5" commonmark "^0.30.0" fs-extra "^9.1.0" + sort-json "^2.0.0" typescript "~3.9.10" + workerpool "^6.1.5" yargs "^16.2.0" -jsii@^1.40.0: - version "1.40.0" - resolved "https://registry.npmjs.org/jsii/-/jsii-1.40.0.tgz#cc04f2bad5ae9495513af921cfcaca99dc8753d3" - integrity sha512-QUPmQzq7c/FREvtfw9+eIU16LB45hxRPtdLO2Ci2ZX1df4E4+vegtfvvjUJ21diVo2hwVp4UCftKqrXZ/cXEFg== +jsii@^1.41.0: + version "1.41.0" + resolved "https://registry.npmjs.org/jsii/-/jsii-1.41.0.tgz#926e033d7ba57c65d6d070dee1d4d19da0fa9508" + integrity sha512-5pjfWjSaMzE+mkpW//llBSGLcXJGNjE0KFSf73USPZTfJC09dBEJ4KJM85SogCNnWHwG5QecEpZStxNvt8GI7g== dependencies: - "@jsii/check-node" "1.40.0" - "@jsii/spec" "^1.40.0" + "@jsii/check-node" "1.41.0" + "@jsii/spec" "^1.41.0" case "^1.6.3" colors "^1.4.0" deep-equal "^2.0.5" @@ -7972,11 +7960,6 @@ null-check@^1.0.0: resolved "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - nwsapi@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" @@ -8113,10 +8096,10 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -oo-ascii-tree@^1.40.0: - version "1.40.0" - resolved "https://registry.npmjs.org/oo-ascii-tree/-/oo-ascii-tree-1.40.0.tgz#69005b8f5f140ed23a81e90b3659750dc3a62522" - integrity sha512-nkiEc8TJZwGxPdEB1jRxHWyc/qBTPQSf70KhO+WjuiWzVfLVEWF/dksWRjm8e510YmPrBjfYCJOn+BVlOUojSQ== +oo-ascii-tree@^1.41.0: + version "1.41.0" + resolved "https://registry.npmjs.org/oo-ascii-tree/-/oo-ascii-tree-1.41.0.tgz#88883d2b8446ded7082a96faf3294e1092aeeb46" + integrity sha512-WxQIFO+JMCIJBlIMUATsp+PW5kqDMy2CD7u5uC9qQk29XInUMO+RN7/QVZJsPHO3o73eJFN9CFc9XDWQJwVKBQ== open@^7.4.2: version "7.4.2" @@ -9599,7 +9582,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@*, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@*, string-width@^1.0.1, "string-width@^1.0.2 || 2", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -9608,23 +9591,6 @@ string-width@*, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - string.prototype.repeat@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz#aba36de08dcee6a5a337d49b2ea1da1b28fc0ecf" @@ -9677,13 +9643,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -10540,6 +10499,11 @@ wordwrap@>=0.0.2, wordwrap@^1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= +workerpool@^6.1.5: + version "6.1.5" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" + integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"