diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 286ca89cb1c53..6835abe99e034 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -15,7 +15,10 @@ description of the bug: ### Reproduction Steps ### What did you expect to happen? diff --git a/CHANGELOG.md b/CHANGELOG.md index 8487aaf34742f..63aa4c3bf3be9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,44 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.103.0](https://github.com/aws/aws-cdk/compare/v1.102.0...v1.103.0) (2021-05-10) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **appmesh:** HealthChecks require use of static factory methods +* **apigatewayv2:** The `metricXXX` methods are no longer available in the +`IApi` interface. The existing ones are moved into `IHttpApi` and new +ones will be added to `IWebsocketApi`. +* **apigatewayv2:** The `metricXXX` methods are no longer available in +the `IStage` interface. The existing ones are moved into `IHttpStage` +and new ones will be added to the `IWebsocketStage`. +* **lambda-nodejs:** the default runtime version for `NodejsFunction` is now always `NODEJS_14_X` (previously the version was derived from the local NodeJS runtime and could be either 12.x or 14.x). + +### Features + +* **appmesh:** change HealthChecks to use protocol-specific union-like classes ([#14432](https://github.com/aws/aws-cdk/issues/14432)) ([063ddc7](https://github.com/aws/aws-cdk/commit/063ddc7315954a2104ac7aa4cb98f96239b8dd1e)) +* **aws-ecs:** Expose logdriver "mode" property ([#13965](https://github.com/aws/aws-cdk/issues/13965)) ([28fce22](https://github.com/aws/aws-cdk/commit/28fce2264448820495d921ed08ae0d3084442876)), closes [#13845](https://github.com/aws/aws-cdk/issues/13845) +* **cloudwatch:** validate parameters for a metric dimensions (closes [#3116](https://github.com/aws/aws-cdk/issues/3116)) ([#14365](https://github.com/aws/aws-cdk/issues/14365)) ([4a24d61](https://github.com/aws/aws-cdk/commit/4a24d61654ef77557350e35443ddab7597d61736)) +* **docdb:** Support multiple security groups to DatabaseCluster ([#13290](https://github.com/aws/aws-cdk/issues/13290)) ([1a97b66](https://github.com/aws/aws-cdk/commit/1a97b6664f9124ec21a6db39be600cee0411ab8c)) +* **elbv2:** preserveClientIp for NetworkTargetGroup ([#14589](https://github.com/aws/aws-cdk/issues/14589)) ([d676ffc](https://github.com/aws/aws-cdk/commit/d676ffccb28d530a18d0e1630df0940632122a27)) +* **kinesis:** Basic stream level metrics ([#12556](https://github.com/aws/aws-cdk/issues/12556)) ([5f1b576](https://github.com/aws/aws-cdk/commit/5f1b57603330e707bc68f56c267a9e45faa29e55)), closes [#12555](https://github.com/aws/aws-cdk/issues/12555) +* **kms:** allow specifying key spec and key usage ([#14478](https://github.com/aws/aws-cdk/issues/14478)) ([10ae1a9](https://github.com/aws/aws-cdk/commit/10ae1a902383e69d15a17585268dd836ffb4087b)), closes [#5639](https://github.com/aws/aws-cdk/issues/5639) +* **lambda-go:** higher level construct for golang lambdas ([#11842](https://github.com/aws/aws-cdk/issues/11842)) ([0948cc7](https://github.com/aws/aws-cdk/commit/0948cc7d4e38ac4e9ae765fcc571ea4f49ca9095)) +* **msk:** Cluster L2 Construct ([#9908](https://github.com/aws/aws-cdk/issues/9908)) ([ce119ba](https://github.com/aws/aws-cdk/commit/ce119ba20d42191fa7ae2e83d459406be16e1748)) + + +### Bug Fixes + +* **apigatewayv2:** incorrect metric names for client and server-side errors ([#14541](https://github.com/aws/aws-cdk/issues/14541)) ([551182e](https://github.com/aws/aws-cdk/commit/551182efb1313425c97088b66c17d6227cb69da6)), closes [#14503](https://github.com/aws/aws-cdk/issues/14503) +* `assert` matches more than the template on multiple CDK copies ([#14544](https://github.com/aws/aws-cdk/issues/14544)) ([f8abdbf](https://github.com/aws/aws-cdk/commit/f8abdbfb37ba9efd9e24414f5b64d90f4cf3f7cb)), closes [#14468](https://github.com/aws/aws-cdk/issues/14468) +* **apigatewayv2-integrations:** fix broken lambda websocket integration uri ([#13820](https://github.com/aws/aws-cdk/issues/13820)) ([f0d5c25](https://github.com/aws/aws-cdk/commit/f0d5c25e1ae026eef03dc396e48368521dcb8331)), closes [#13679](https://github.com/aws/aws-cdk/issues/13679) +* **cfn-include:** correctly parse Fn::Sub expressions containing serialized JSON ([#14512](https://github.com/aws/aws-cdk/issues/14512)) ([fd6d6d0](https://github.com/aws/aws-cdk/commit/fd6d6d0a563816ace616dfe48b3a03f4559636f7)), closes [#14095](https://github.com/aws/aws-cdk/issues/14095) +* **cli:** 'cdk deploy *' should not deploy stacks in nested assemblies ([#14542](https://github.com/aws/aws-cdk/issues/14542)) ([93a3549](https://github.com/aws/aws-cdk/commit/93a3549e7a9791b5074dc95909f3289970800c10)) +* **cli:** synth fails if there was an error when synthesizing the stack ([#14613](https://github.com/aws/aws-cdk/issues/14613)) ([71c61e8](https://github.com/aws/aws-cdk/commit/71c61e81ca58c95979f66d7d7b8100777d3c7b99)) +* **lambda-nodejs:** non-deterministic runtime version ([#14538](https://github.com/aws/aws-cdk/issues/14538)) ([527f662](https://github.com/aws/aws-cdk/commit/527f6622146f007035ca669c33ad73861afe608a)), closes [#13893](https://github.com/aws/aws-cdk/issues/13893) +* **ssm:** dynamic SSM parameter reference breaks with lists ([#14527](https://github.com/aws/aws-cdk/issues/14527)) ([3d1baac](https://github.com/aws/aws-cdk/commit/3d1baaca015443d7ee0eecdec9e81dd61e8920ad)), closes [#14205](https://github.com/aws/aws-cdk/issues/14205) [#14476](https://github.com/aws/aws-cdk/issues/14476) + ## [1.102.0](https://github.com/aws/aws-cdk/compare/v1.101.0...v1.102.0) (2021-05-04) diff --git a/package.json b/package.json index 950db71bee203..0b56f8c255e56 100644 --- a/package.json +++ b/package.json @@ -21,18 +21,19 @@ "fs-extra": "^9.1.0", "graceful-fs": "^4.2.6", "jest-junit": "^12.0.0", - "jsii-diff": "^1.28.0", - "jsii-pacmak": "^1.28.0", - "jsii-rosetta": "^1.28.0", - "jsii-reflect": "^1.28.0", + "jsii-diff": "^1.29.0", + "jsii-pacmak": "^1.29.0", + "jsii-reflect": "^1.29.0", + "jsii-rosetta": "^1.29.0", "lerna": "^4.0.0", "patch-package": "^6.4.7", - "standard-version": "^9.2.0", + "standard-version": "^9.3.0", "typescript": "~3.9.9" }, "tap-mocha-reporter-resolutions-comment": "should be removed or reviewed when nodeunit dependency is dropped or adjusted", "resolutions": { - "tap-mocha-reporter": "^5.0.1" + "tap-mocha-reporter": "^5.0.1", + "string-width": "^4.2.2" }, "repository": { "type": "git", diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/environment.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/environment.ts index d83c286f0cdd6..85247062cde7b 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/environment.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/environment.ts @@ -8,18 +8,19 @@ import { EnvironmentCapacityType } from './extensions/extension-interfaces'; import { Construct } from '@aws-cdk/core'; /** - * Settings for the environment you want to deploy. - * services within. + * Settings for the environment where you want to deploy your services. */ export interface EnvironmentProps { /** - * The VPC used by the service for networking + * The VPC used by the service for networking. + * * @default - Create a new VPC */ readonly vpc?: ec2.IVpc, /** * The ECS cluster which provides compute capacity to this service. + * * [disable-awslint:ref-via-interface] * @default - Create a new cluster */ @@ -27,6 +28,7 @@ export interface EnvironmentProps { /** * The type of capacity to use for this environment. + * * @default - EnvironmentCapacityType.FARGATE */ readonly capacityType?: EnvironmentCapacityType @@ -64,8 +66,8 @@ export interface IEnvironment { /** * An environment into which to deploy a service. This environment - * can either be instantiated with a preexisting AWS VPC and ECS cluster, - * or it can create it's own VPC and cluster. By default it will create + * can either be instantiated with a pre-existing AWS VPC and ECS cluster, + * or it can create its own VPC and cluster. By default, it will create * a cluster with Fargate capacity. */ export class Environment extends Construct implements IEnvironment { @@ -82,7 +84,7 @@ export class Environment extends Construct implements IEnvironment { public readonly id: string; /** - * The VPC into which environment services should be placed. + * The VPC where environment services should be placed. */ public readonly vpc: ec2.IVpc; @@ -159,10 +161,10 @@ export class ImportedEnvironment extends Construct implements IEnvironment { } /** - * Refuses to add a default cloudmap namespace to the cluster as we don't + * Adding a default cloudmap namespace to the cluster will throw an error, as we don't * own it. */ addDefaultCloudMapNamespace(_options: ecs.CloudMapNamespaceOptions) { throw new Error('the cluster environment is immutable when imported'); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/appmesh.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/appmesh.ts index 95220dc1ea3b4..5442cb4fd6d15 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/appmesh.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/appmesh.ts @@ -21,7 +21,7 @@ const APP_MESH_ENVOY_SIDECAR_VERSION = 'v1.15.1.0-prod'; */ export interface MeshProps { /** - * The service mesh into which to register the service + * The service mesh into which to register the service. */ readonly mesh: appmesh.Mesh; @@ -39,9 +39,9 @@ export interface MeshProps { * to the container in a service mesh. * * The service will then be available to other App Mesh services at the - * address `.`. For example a service called + * address `.`. For example, a service called * `orders` deploying in an environment called `production` would be accessible - * to other App Mesh enabled services at the address `http://orders.production` + * to other App Mesh enabled services at the address `http://orders.production`. */ export class AppMeshExtension extends ServiceExtension { protected virtualNode!: appmesh.VirtualNode; @@ -249,7 +249,7 @@ export class AppMeshExtension extends ServiceExtension { } as ServiceBuild; } - // Now that the service is defined we can create the AppMesh virtual service + // Now that the service is defined, we can create the AppMesh virtual service // and virtual node for the real service public useService(service: ecs.Ec2Service | ecs.FargateService) { const containerextension = this.parentService.serviceDescription.get('service-container') as Container; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/cloudwatch-agent.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/cloudwatch-agent.ts index ceed938e995cb..9096b43aabd3a 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/cloudwatch-agent.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/cloudwatch-agent.ts @@ -11,7 +11,7 @@ const CLOUDWATCH_AGENT_IMAGE = 'amazon/cloudwatch-agent:latest'; /** * This extension adds a CloudWatch agent to the task definition and - * configures the task to be able to publish metrics to CloudWatch + * configures the task to be able to publish metrics to CloudWatch. */ export class CloudwatchAgentExtension extends ServiceExtension { private CW_CONFIG_CONTENT = { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts index 1bbc61ff4f8f7..10c61401e90d3 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/container.ts @@ -7,32 +7,33 @@ import { ServiceExtension } from './extension-interfaces'; import { Construct } from '@aws-cdk/core'; /** - * Setting for the main application container of a service + * Setting for the main application container of a service. */ export interface ContainerExtensionProps { /** - * How much CPU the container requires + * How much CPU the container requires. */ readonly cpu: number, /** - * How much memory in megabytes the container requires + * How much memory in megabytes the container requires. */ readonly memoryMiB: number, /** - * The image to run + * The image to run. */ readonly image: ecs.ContainerImage, /** - * What port the image listen for traffic on + * What port the image listen for traffic on. */ readonly trafficPort: number, /** - * Environment variables to pass into the container - * @default - No environment variables + * Environment variables to pass into the container. + * + * @default - No environment variables. */ readonly environment?: { [key: string]: string, @@ -51,7 +52,7 @@ export class Container extends ServiceExtension { public readonly trafficPort: number; /** - * The settings for the container + * The settings for the container. */ private props: ContainerExtensionProps; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/extension-interfaces.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/extension-interfaces.ts index fa0d42602c563..8e70a53a59d8e 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/extension-interfaces.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/extension-interfaces.ts @@ -7,77 +7,83 @@ import { Service } from '../service'; import { Construct } from '@aws-cdk/core'; /** - * A list of the capacity types that are supported. These - * capacity types may change the behavior of an extension. + * The types of capacity that are supported. These capacity types may change the + * behavior of an extension. */ export enum EnvironmentCapacityType { /** * Specify that the environment should use AWS Fargate for - * hosting containers + * hosting containers. */ FARGATE = 'fargate', /** * Specify that the environment should launch containers onto - * EC2 instances + * EC2 instances. */ EC2 = 'ec2' } /** - * A service props that is in the process of being assembled - * Eventually to be assigned to a ecs.Ec2ServiceProps - * or ecs.FargateServiceProps depending on the environment's - * capacity type. + * A set of mutable service props in the process of being assembled using a + * builder pattern. They will eventually to be translated into an + * ecs.Ec2ServiceProps or ecs.FargateServiceProps interface, depending on the + * environment's capacity type. */ export interface ServiceBuild { /** - * The cluster in which to add the service + * The cluster in which to launch the service. */ readonly cluster: ecs.ICluster, /** - * The task definition registered to this service + * The task definition registered to this service. */ readonly taskDefinition: ecs.TaskDefinition, /** - * Specifies whether the task's elastic network interface receives a public IP address. + * Specifies whether the task's elastic network interface receives a public IP + * address. * * If true, each task will receive a public IP address. * - * @default false + * @default - false */ readonly assignPublicIp?: boolean; /** - * Configuration for how to register the service in service discovery + * Configuration for how to register the service in service discovery. + * * @default - No Cloud Map configured */ readonly cloudMapOptions?: ecs.CloudMapOptions /** - * During initial task startup how long the healthcheck can fail before + * How long the healthcheck can fail during initial task startup before * the task is considered unhealthy. This is used to give the task more - * time to start passing healthchecks + * time to start passing healthchecks. + * * @default - No grace period */ readonly healthCheckGracePeriod?: cdk.Duration, /** - * How many tasks to run + * How many tasks to run. + * * @default - 1 */ readonly desiredCount?: number; /** - * Minimum healthy task percentage + * Minimum healthy task percentage. + * * @default - 100 */ readonly minHealthyPercent?: number; /** - * Maximum percentage of tasks that can be launched + * Maximum percentage of tasks that can be launched. + * * @default - 200 */ readonly maxHealthyPercent?: number; @@ -85,27 +91,27 @@ export interface ServiceBuild { /** * The shape of a service extension. This abstract class is implemented - * by other extensions which extend the hooks to implement their own - * logic that they want to run during each step of preparing the service + * by other extensions that extend the hooks to implement any custom + * logic that they want to run during each step of preparing the service. */ export abstract class ServiceExtension { /** - * The name of the extension + * The name of the extension. */ public name: string; /** - * The container of this extension. Most extensions have a container, but not - * every extension is required to have a container, some extensions may just + * The container for this extension. Most extensions have a container, but not + * every extension is required to have a container. Some extensions may just * modify the properties of the service, or create external resources - * connected to the service + * connected to the service. */ public container?: ecs.ContainerDefinition; /** - * The service which this extension is applying itself to. - * Initially extensions are added to a ServiceDescription, but no service - * exists yet. Later when the ServiceDescription is used to create a service, + * The service which this extension is being added to. + * Initially, extensions are collected into a ServiceDescription, but no service + * exists yet. Later, when the ServiceDescription is used to create a service, * the extension is told what Service it is now working on. */ protected parentService!: Service; @@ -121,16 +127,17 @@ export abstract class ServiceExtension { /** * A hook that allows the extension to add hooks to other - * extensions that are registered + * extensions that are registered. */ public addHooks() { } // tslint:disable-line /** * This hook allows another service extension to register a mutating hook for * changing the primary container of this extension. This is primarily used - * for the application extension. For example the Firelens extension wants to + * for the application extension. For example, the Firelens extension wants to * be able to modify the settings of the application container to * route logs through Firelens. + * * @param hook */ public addContainerMutatingHook(hook: ContainerMutatingHook) { @@ -139,10 +146,11 @@ export abstract class ServiceExtension { /** * This is a hook which allows extensions to modify the settings of the - * task definition prior to it being created. For example App Mesh + * task definition prior to it being created. For example, the App Mesh * extension needs to configure an Envoy proxy in the task definition, - * or the application extension wants to set the overall resource for + * or the Application extension wants to set the overall resource for * the task. + * * @param props - Properties of the task definition to be created */ public modifyTaskDefinitionProps(props: ecs.TaskDefinitionProps): ecs.TaskDefinitionProps { @@ -152,9 +160,10 @@ export abstract class ServiceExtension { } /** - * A hook that is called for each extension adhead of time to - * let it do any initial setup, such as creating resources in + * A hook that is called for each extension ahead of time to + * allow for any initial setup, such as creating resources in * advance. + * * @param parent - The parent service which this extension has been added to * @param scope - The scope that this extension should create resources in */ @@ -166,7 +175,8 @@ export abstract class ServiceExtension { /** * Once the task definition is created, this hook is called for each * extension to give it a chance to add containers to the task definition, - * change the task definition's role to add permissions, etc + * change the task definition's role to add permissions, etc. + * * @param taskDefinition - The created task definition to add containers to */ public useTaskDefinition(taskDefinition: ecs.TaskDefinition) { @@ -174,20 +184,21 @@ export abstract class ServiceExtension { } /** - * Once all containers are added to the task definition this hook is + * Once all containers are added to the task definition, this hook is * called for each extension to give it a chance to resolve its dependency * graph so that its container starts in the right order based on the - * other extensions that were enabled + * other extensions that were enabled. */ public resolveContainerDependencies() { return; } /** - * Prior to launching the task definition as a service this hook + * Prior to launching the task definition as a service, this hook * is called on each extension to give it a chance to mutate the properties - * of the service to be created - * @param props - The service properties to mutate + * of the service to be created. + * + * @param props - The service properties to mutate. */ public modifyServiceProps(props: ServiceBuild): ServiceBuild { return { @@ -196,10 +207,11 @@ export abstract class ServiceExtension { } /** - * When this hook is implemented by extension it allows the extension + * When this hook is implemented by extension, it allows the extension * to use the service which has been created. It is generally used to - * create any final resources which might depend on the service itself - * @param service - The generated service + * create any final resources which might depend on the service itself. + * + * @param service - The generated service. */ public useService(service: ecs.Ec2Service | ecs.FargateService) { service = service; @@ -210,7 +222,8 @@ export abstract class ServiceExtension { * extensions from another service. Usually used for things like * allowing one service to talk to the load balancer or service mesh * proxy for another service. - * @param service - The other service to connect to + * + * @param service - The other service to connect to. */ public connectToService(service: Service) { service = service; @@ -224,10 +237,11 @@ export abstract class ServiceExtension { export abstract class ContainerMutatingHook { /** * This is a hook for modifying the container definition of any upstream - * containers. This is primarily used for the application extension. - * For example the Firelens extension wants to be able to modify the logging + * containers. This is primarily used for the main application container. + * For example, the Firelens extension wants to be able to modify the logging * settings of the application container. - * @param props - The container definition to mutate + * + * @param props - The container definition to mutate. */ public mutateContainerDefinition(props: ecs.ContainerDefinitionOptions): ecs.ContainerDefinitionOptions { return { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/firelens.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/firelens.ts index 1dfc8e1f1b0b0..2e5f31c7af3d2 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/firelens.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/firelens.ts @@ -11,23 +11,23 @@ import { Construct } from '@aws-cdk/core'; /** * Settings for the hook which mutates the application container - * to route logs through FireLens + * to route logs through FireLens. */ export interface FirelensProps { /** - * The parent service that is being mutated + * The parent service that is being mutated. */ readonly parentService: Service; /** - * The log group into which logs should be routed + * The log group into which logs should be routed. */ readonly logGroup: awslogs.LogGroup; } /** * This hook modifies the application container's settings so that - * it routes logs using FireLens + * it routes logs using FireLens. */ export class FirelensMutatingHook extends ContainerMutatingHook { private parentService: Service; @@ -58,7 +58,7 @@ export class FirelensMutatingHook extends ContainerMutatingHook { /** * This extension adds a FluentBit log router to the task definition * and does all the configuration necessarily to enable log routing - * for the task using FireLens + * for the task using FireLens. */ export class FireLensExtension extends ServiceExtension { private logGroup!: awslogs.LogGroup; @@ -127,4 +127,4 @@ export class FireLensExtension extends ServiceExtension { }); } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/http-load-balancer.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/http-load-balancer.ts index 884477b4d38db..e0390c0ab617c 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/http-load-balancer.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/http-load-balancer.ts @@ -10,7 +10,7 @@ import { Construct } from '@aws-cdk/core'; /** * This extension add a public facing load balancer for sending traffic - * to one or more replicas of the application container + * to one or more replicas of the application container. */ export class HttpLoadBalancerExtension extends ServiceExtension { private loadBalancer!: alb.IApplicationLoadBalancer; @@ -20,7 +20,7 @@ export class HttpLoadBalancerExtension extends ServiceExtension { super('load-balancer'); } - // Before the service is created go ahead and create the load balancer itself. + // Before the service is created, go ahead and create the load balancer itself. public prehook(service: Service, scope: Construct) { this.parentService = service; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/scale-on-cpu-utilization.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/scale-on-cpu-utilization.ts index c0ee8b0e12ac0..ec6ce9662535f 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/scale-on-cpu-utilization.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/scale-on-cpu-utilization.ts @@ -3,41 +3,47 @@ import * as cdk from '@aws-cdk/core'; import { ServiceExtension, ServiceBuild } from './extension-interfaces'; /** - * The autoscaling settings + * The autoscaling settings. */ export interface CpuScalingProps { /** - * How many tasks to launch initially + * How many tasks to launch initially. + * * @default - 2 */ readonly initialTaskCount?: number; /** - * The minimum number of tasks when scaling in + * The minimum number of tasks when scaling in. + * * @default - 2 */ readonly minTaskCount?: number; /** - * The maximum number of tasks when scaling out + * The maximum number of tasks when scaling out. + * * @default - 8 */ readonly maxTaskCount?: number; /** - * The CPU utilization to try ot maintain + * The CPU utilization to try ot maintain. + * * @default - 50% */ readonly targetCpuUtilization?: number; /** - * How long to wait between scale out actions + * How long to wait between scale out actions. + * * @default - 60 seconds */ readonly scaleOutCooldown?: cdk.Duration; /** - * How long to wait between scale in actions + * How long to wait between scale in actions. + * * @default - 60 seconds */ readonly scaleInCooldown?: cdk.Duration; @@ -54,36 +60,36 @@ const cpuScalingPropsDefault = { }; /** - * This extension helps you scale your service according to CPU utilization + * This extension helps you scale your service according to CPU utilization. */ export class ScaleOnCpuUtilization extends ServiceExtension { /** - * How many tasks to launch initially + * How many tasks to launch initially. */ public readonly initialTaskCount: number; /** - * The minimum number of tasks when scaling in + * The minimum number of tasks when scaling in. */ public readonly minTaskCount: number; /** - * The maximum number of tasks when scaling out + * The maximum number of tasks when scaling out. */ public readonly maxTaskCount: number; /** - * The CPU utilization to try ot maintain + * The CPU utilization to try ot maintain. */ public readonly targetCpuUtilization: number; /** - * How long to wait between scale out actions + * How long to wait between scale out actions. */ public readonly scaleOutCooldown: cdk.Duration; /** - * How long to wait between scale in actions + * How long to wait between scale in actions. */ public readonly scaleInCooldown: cdk.Duration; @@ -118,7 +124,7 @@ export class ScaleOnCpuUtilization extends ServiceExtension { } // This hook utilizes the resulting service construct - // once it is created + // once it is created. public useService(service: ecs.Ec2Service | ecs.FargateService) { const scalingTarget = service.autoScaleTaskCount({ minCapacity: this.minTaskCount, @@ -131,4 +137,4 @@ export class ScaleOnCpuUtilization extends ServiceExtension { scaleOutCooldown: this.scaleOutCooldown, }); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/xray.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/xray.ts index 5e9affe0ffa3a..6b902a8c004d8 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/xray.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/xray.ts @@ -11,7 +11,7 @@ import { Construct } from '@aws-cdk/core'; const XRAY_DAEMON_IMAGE = 'amazon/aws-xray-daemon:latest'; /** - * This extension adds an X-Ray daemon inside the task definition, for + * This extension adds an X-Ray daemon inside the task definition for * capturing application trace spans and submitting them to the AWS * X-Ray service. */ @@ -67,4 +67,4 @@ export class XRayExtension extends ServiceExtension { }); } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service-description.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service-description.ts index 597b6ac6fe5d0..eb26905a5baa9 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service-description.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service-description.ts @@ -1,11 +1,10 @@ import { ServiceExtension } from './extensions/extension-interfaces'; /** - * A description of a service to construct. This construct collects - * all of the extensions that a user wants to add to their Service. - * It is used as a shared collection of all the extensions, allowing - * extensions to query the full list of extensions to determine - * information about how to self configure. + * A ServiceDescription is a wrapper for all of the extensions that a user wants + * to add to an ECS Service. It collects all of the extensions that are added + * to a service, allowing each extension to query the full list of extensions + * added to a service to determine information about how to self-configure. */ export class ServiceDescription { /** @@ -16,7 +15,8 @@ export class ServiceDescription { /** * Adds a new extension to the service. The extensions mutate a service - * to add resources or features to the service + * to add resources to or configure properties for the service. + * * @param extension - The extension that you wish to add */ public add(extension: ServiceExtension) { @@ -30,11 +30,12 @@ export class ServiceDescription { } /** - * Get the extension with a specific name. This is generally used for - * extensions to discover each other's existence. + * Get the extension with a specific name. This is generally used by + * extensions in order to discover each other. + * * @param name */ public get(name: string) { return this.extensions[name]; } -}; \ No newline at end of file +}; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts index c988c0592b6bf..03c79528ab5d4 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts @@ -10,69 +10,71 @@ import { ServiceDescription } from './service-description'; import { Construct } from '@aws-cdk/core'; /** - * The settings for an ECS Service + * The settings for an ECS Service. */ export interface ServiceProps { /** - * A service description to use in building out the service + * The ServiceDescription used to build the service. */ readonly serviceDescription: ServiceDescription; /** - * The environment to launch the service in + * The environment to launch the service in. */ readonly environment: IEnvironment } /** - * A service builder class. This construct support various extensions - * which can construct an ECS service progressively. + * This Service construct serves as a Builder class for an ECS service. It + * supports various extensions and keeps track of any mutating state, allowing + * it to build up an ECS service progressively. */ export class Service extends Construct { /** - * The underlying ECS service that was created + * The underlying ECS service that was created. */ public ecsService!: ecs.Ec2Service | ecs.FargateService; /** - * The name of this service + * The name of the service. */ public readonly id: string; /** - * The VPC into which this service should be placed + * The VPC where this service should be placed. */ public readonly vpc: ec2.IVpc; /** - * The cluster that is providing capacity for this service + * The cluster that is providing capacity for this service. * [disable-awslint:ref-via-interface] */ public readonly cluster: ecs.ICluster; /** - * The capacity type that this service will use + * The capacity type that this service will use. + * Valid values are EC2 or FARGATE. */ public readonly capacityType: EnvironmentCapacityType; /** - * The service description used to build this service + * The ServiceDescription used to build this service. */ public readonly serviceDescription: ServiceDescription; /** - * The environment this service was launched in + * The environment where this service was launched. */ public readonly environment: IEnvironment; /** - * The generated task definition for this service, is only - * generated once .prepare() has been executed + * The generated task definition for this service. It is only + * generated after .prepare() has been executed. */ protected taskDefinition!: ecs.TaskDefinition; /** - * The list of URL's associated with this service + * The list of URLs associated with this service. */ private urls: Record = {}; @@ -215,7 +217,8 @@ export class Service extends Construct { /** * Tell extensions from one service to connect to extensions from - * another sevice if they have implemented a hook for that. + * another sevice if they have implemented a hook for it. + * * @param service */ public connectTo(service: Service) { @@ -227,9 +230,10 @@ export class Service extends Construct { } /** - * This method adds a new URL for the service. This allows extensions - * to submit a URL for the service, for example LB might add its URL - * or App Mesh can add its DNS name for the service. + * This method adds a new URL for the service. This allows extensions to + * submit a URL for the service. For example, a load balancer might add its + * URL, or App Mesh can add its DNS name for the service. + * * @param urlName - The identifier name for this URL * @param url - The URL itself. */ @@ -240,6 +244,7 @@ export class Service extends Construct { /** * Retrieve a URL for the service. The URL must have previously been * stored by one of the URL providing extensions. + * * @param urlName - The URL to look up. */ public getURL(urlName: string) { @@ -249,4 +254,4 @@ export class Service extends Construct { return this.urls[urlName]; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json index a3ca1613f58a7..47ba97c3ee10d 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/integ.all-service-addons.expected.json @@ -765,7 +765,9 @@ "FirelensConfiguration": { "Type": "fluentbit" }, - "Image": "{{resolve:ssm:/aws/service/aws-for-fluent-bit/latest}}", + "Image": { + "Ref": "SsmParameterValueawsserviceawsforfluentbitlatestC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "LogConfiguration": { "LogDriver": "awslogs", "Options": { @@ -1632,7 +1634,9 @@ "FirelensConfiguration": { "Type": "fluentbit" }, - "Image": "{{resolve:ssm:/aws/service/aws-for-fluent-bit/latest}}", + "Image": { + "Ref": "SsmParameterValueawsserviceawsforfluentbitlatestC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "LogConfiguration": { "LogDriver": "awslogs", "Options": { @@ -2618,7 +2622,9 @@ "FirelensConfiguration": { "Type": "fluentbit" }, - "Image": "{{resolve:ssm:/aws/service/aws-for-fluent-bit/latest}}", + "Image": { + "Ref": "SsmParameterValueawsserviceawsforfluentbitlatestC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "LogConfiguration": { "LogDriver": "awslogs", "Options": { @@ -3478,6 +3484,12 @@ } } }, + "Parameters": { + "SsmParameterValueawsserviceawsforfluentbitlatestC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/aws-for-fluent-bit/latest" + } + }, "Outputs": { "greeterloadbalancerdnsoutput": { "Value": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.firelens.ts b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.firelens.ts index 897cc7e9eb892..a6011a2caabf6 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/test/test.firelens.ts +++ b/packages/@aws-cdk-containers/ecs-service-extensions/test/test.firelens.ts @@ -80,7 +80,9 @@ export = { FirelensConfiguration: { Type: 'fluentbit', }, - Image: '{{resolve:ssm:/aws/service/aws-for-fluent-bit/latest}}', + Image: { + Ref: 'SsmParameterValueawsserviceawsforfluentbitlatestC96584B6F00A464EAD1953AFF4B05118Parameter', + }, LogConfiguration: { LogDriver: 'awslogs', Options: { @@ -117,4 +119,4 @@ export = { test.done(); }, -}; +}; \ No newline at end of file diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index 57ff061fc6601..c4ed29f9a533a 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/assert-internal/lib/synth-utils.ts b/packages/@aws-cdk/assert-internal/lib/synth-utils.ts index bb8d9a437afd9..d8dc73aff881a 100644 --- a/packages/@aws-cdk/assert-internal/lib/synth-utils.ts +++ b/packages/@aws-cdk/assert-internal/lib/synth-utils.ts @@ -18,7 +18,7 @@ export class SynthUtils { */ public static toCloudFormation(stack: core.Stack, options: core.SynthesisOptions = { }): any { const synth = this._synthesizeWithNested(stack, options); - if (synth instanceof cxapi.CloudFormationStackArtifact) { + if (isStackArtifact(synth)) { return synth.template; } else { return synth; @@ -85,3 +85,7 @@ export interface SubsetOptions { */ resourceTypes?: string[]; } + +function isStackArtifact(x: object): x is cxapi.CloudFormationStackArtifact { + return 'template' in x; +} \ No newline at end of file diff --git a/packages/@aws-cdk/assert-internal/package.json b/packages/@aws-cdk/assert-internal/package.json index 7b96667edc773..457b39b567656 100644 --- a/packages/@aws-cdk/assert-internal/package.json +++ b/packages/@aws-cdk/assert-internal/package.json @@ -22,11 +22,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.6" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index c0fe40edc0d4c..110f058431b5f 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -34,13 +34,13 @@ "license": "Apache-2.0", "devDependencies": { "aws-cdk-migration": "0.0.0", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "constructs": "^3.3.69", "jest": "^26.6.3", "pkglint": "0.0.0", "@aws-cdk/assert-internal": "0.0.0", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.6" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0", diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index 6d23cff904645..e962ce96ebf94 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -75,7 +75,7 @@ "nodeunit": "^0.11.3", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-mock-imports": "^1.3.3", + "ts-mock-imports": "^1.3.4", "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-accessanalyzer/package.json b/packages/@aws-cdk/aws-accessanalyzer/package.json index 1ac8ee40b8184..62e09ba13324c 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/package.json +++ b/packages/@aws-cdk/aws-accessanalyzer/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-acmpca/package.json b/packages/@aws-cdk/aws-acmpca/package.json index 53e9847bf41d9..f6f5480861408 100644 --- a/packages/@aws-cdk/aws-acmpca/package.json +++ b/packages/@aws-cdk/aws-acmpca/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-amazonmq/package.json b/packages/@aws-cdk/aws-amazonmq/package.json index 98cd42e3e4b39..c3c54803650df 100644 --- a/packages/@aws-cdk/aws-amazonmq/package.json +++ b/packages/@aws-cdk/aws-amazonmq/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index 4fb1fd09b9da5..24aa0753df720 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 2249d40beb18c..ba8b777cf68ba 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index 6daecfe1447fb..c70e7a5dd8115 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts index 85e199a71c3d7..8dedb470ce6af 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/lib/websocket/lambda.ts @@ -36,9 +36,16 @@ export class LambdaWebSocketIntegration implements IWebSocketRouteIntegration { }), }); + const integrationUri = Stack.of(route).formatArn({ + service: 'apigateway', + account: 'lambda', + resource: 'path/2015-03-31/functions', + resourceName: `${this.props.handler.functionArn}/invocations`, + }); + return { type: WebSocketIntegrationType.AWS_PROXY, - uri: this.props.handler.functionArn, + uri: integrationUri, }; } } diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index 8eb5e63c8c3a0..b3f98aa94a520 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -69,7 +69,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json index 48bf164ada435..54a0f51203342 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/integ.lambda.expected.json @@ -245,7 +245,7 @@ } } }, - "mywsapiconnectRouteWebSocketIntegration50b017444a02be00a0b575d123314581176017EE": { + "mywsapiconnectRouteWebSocketIntegration3025fc0297cc8d73dae555b46106edcd38569D62": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -253,9 +253,26 @@ }, "IntegrationType": "AWS_PROXY", "IntegrationUri": { - "Fn::GetAtt": [ - "ConnectHandler2FFD52D8", - "Arn" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "ConnectHandler2FFD52D8", + "Arn" + ] + }, + "/invocations" + ] ] } } @@ -273,7 +290,7 @@ [ "integrations/", { - "Ref": "mywsapiconnectRouteWebSocketIntegration50b017444a02be00a0b575d123314581176017EE" + "Ref": "mywsapiconnectRouteWebSocketIntegration3025fc0297cc8d73dae555b46106edcd38569D62" } ] ] @@ -317,7 +334,7 @@ } } }, - "mywsapidisconnectRouteWebSocketIntegrationcd3bacb451e82549501e141cc094d7ba1F7F68BC": { + "mywsapidisconnectRouteWebSocketIntegrationfc84ffd6c52488b90783abae35d28ebdAE5C6063": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -325,9 +342,26 @@ }, "IntegrationType": "AWS_PROXY", "IntegrationUri": { - "Fn::GetAtt": [ - "DisconnectHandlerCB7ED6F7", - "Arn" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "DisconnectHandlerCB7ED6F7", + "Arn" + ] + }, + "/invocations" + ] ] } } @@ -345,7 +379,7 @@ [ "integrations/", { - "Ref": "mywsapidisconnectRouteWebSocketIntegrationcd3bacb451e82549501e141cc094d7ba1F7F68BC" + "Ref": "mywsapidisconnectRouteWebSocketIntegrationfc84ffd6c52488b90783abae35d28ebdAE5C6063" } ] ] @@ -389,7 +423,7 @@ } } }, - "mywsapidefaultRouteWebSocketIntegration640ac0772c157aa8b9a56aa99adbd9d7A2B7F2FA": { + "mywsapidefaultRouteWebSocketIntegrationa07b7cec9837e31a8c70446e1e1f1fd5055B3083": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -397,9 +431,26 @@ }, "IntegrationType": "AWS_PROXY", "IntegrationUri": { - "Fn::GetAtt": [ - "DefaultHandler604DF7AC", - "Arn" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "DefaultHandler604DF7AC", + "Arn" + ] + }, + "/invocations" + ] ] } } @@ -417,7 +468,7 @@ [ "integrations/", { - "Ref": "mywsapidefaultRouteWebSocketIntegration640ac0772c157aa8b9a56aa99adbd9d7A2B7F2FA" + "Ref": "mywsapidefaultRouteWebSocketIntegrationa07b7cec9837e31a8c70446e1e1f1fd5055B3083" } ] ] @@ -461,7 +512,7 @@ } } }, - "mywsapisendmessageRouteWebSocketIntegrationcf58a195e318f43f52c4d9ac6d6d2430786B6471": { + "mywsapisendmessageRouteWebSocketIntegrationeb46e3593c10ed57eb0ca9ef3247823d74153661": { "Type": "AWS::ApiGatewayV2::Integration", "Properties": { "ApiId": { @@ -469,9 +520,26 @@ }, "IntegrationType": "AWS_PROXY", "IntegrationUri": { - "Fn::GetAtt": [ - "MessageHandlerDFBBCD6B", - "Arn" + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "MessageHandlerDFBBCD6B", + "Arn" + ] + }, + "/invocations" + ] ] } } @@ -489,7 +557,7 @@ [ "integrations/", { - "Ref": "mywsapisendmessageRouteWebSocketIntegrationcf58a195e318f43f52c4d9ac6d6d2430786B6471" + "Ref": "mywsapisendmessageRouteWebSocketIntegrationeb46e3593c10ed57eb0ca9ef3247823d74153661" } ] ] diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts index 8da4dfa8ec2f5..d5d7e4079db2d 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/test/websocket/lambda.test.ts @@ -21,7 +21,29 @@ describe('LambdaWebSocketIntegration', () => { // THEN expect(stack).toHaveResource('AWS::ApiGatewayV2::Integration', { IntegrationType: 'AWS_PROXY', - IntegrationUri: stack.resolve(fooFn.functionArn), + IntegrationUri: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':apigateway:', + { + Ref: 'AWS::Region', + }, + ':lambda:path/2015-03-31/functions/', + { + 'Fn::GetAtt': [ + 'Fn9270CBC0', + 'Arn', + ], + }, + '/invocations', + ], + ], + }, }); }); }); diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/common/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/common/api.ts index c632e6309083d..8e6089d3cf419 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/common/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/common/api.ts @@ -23,49 +23,4 @@ export interface IApi extends IResource { * @default - average over 5 minutes */ metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the number of client-side errors captured in a given period. - * - * @default - sum over 5 minutes - */ - metricClientError(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the number of server-side errors captured in a given period. - * - * @default - sum over 5 minutes - */ - metricServerError(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the amount of data processed in bytes. - * - * @default - sum over 5 minutes - */ - metricDataProcessed(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the total number API requests in a given period. - * - * @default - SampleCount over 5 minutes - */ - metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * Metric for the time between when API Gateway relays a request to the backend - * and when it receives a response from the backend. - * - * @default - no statistic - */ - metricIntegrationLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; - - /** - * The time between when API Gateway receives a request from a client - * and when it returns a response to the client. - * The latency includes the integration latency and other API Gateway overhead. - * - * @default - no statistic - */ - metricLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; } diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts index 542fcfb16f8f4..cd88fceba46b8 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/common/base.ts @@ -25,30 +25,6 @@ export abstract class ApiBase extends Resource implements IApi { ...props, }).attachTo(this); } - - public metricClientError(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('4XXError', { statistic: 'Sum', ...props }); - } - - public metricServerError(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('5XXError', { statistic: 'Sum', ...props }); - } - - public metricDataProcessed(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('DataProcessed', { statistic: 'Sum', ...props }); - } - - public metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('Count', { statistic: 'SampleCount', ...props }); - } - - public metricIntegrationLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('IntegrationLatency', props); - } - - public metricLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('Latency', props); - } } @@ -84,28 +60,4 @@ export abstract class StageBase extends Resource implements IStage { dimensions: { ApiId: this.baseApi.apiId, Stage: this.stageName }, }).attachTo(this); } - - public metricClientError(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('4XXError', { statistic: 'Sum', ...props }); - } - - public metricServerError(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('5XXError', { statistic: 'Sum', ...props }); - } - - public metricDataProcessed(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('DataProcessed', { statistic: 'Sum', ...props }); - } - - public metricCount(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('Count', { statistic: 'SampleCount', ...props }); - } - - public metricIntegrationLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('IntegrationLatency', props); - } - - public metricLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric { - return this.metric('Latency', props); - } } diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts index 40b7832418633..69f84a40da5e4 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts @@ -23,51 +23,6 @@ export interface IStage extends IResource { * @default - average over 5 minutes */ metric(metricName: string, props?: MetricOptions): Metric - - /** - * Metric for the number of client-side errors captured in a given period. - * - * @default - sum over 5 minutes - */ - metricClientError(props?: MetricOptions): Metric - - /** - * Metric for the number of server-side errors captured in a given period. - * - * @default - sum over 5 minutes - */ - metricServerError(props?: MetricOptions): Metric - - /** - * Metric for the amount of data processed in bytes. - * - * @default - sum over 5 minutes - */ - metricDataProcessed(props?: MetricOptions): Metric - - /** - * Metric for the total number API requests in a given period. - * - * @default - SampleCount over 5 minutes - */ - metricCount(props?: MetricOptions): Metric - - /** - * Metric for the time between when API Gateway relays a request to the backend - * and when it receives a response from the backend. - * - * @default - no statistic - */ - metricIntegrationLatency(props?: MetricOptions): Metric - - /** - * The time between when API Gateway receives a request from a client - * and when it returns a response to the client. - * The latency includes the integration latency and other API Gateway overhead. - * - * @default - no statistic - */ - metricLatency(props?: MetricOptions): Metric } /** diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index 9675a7654a712..73abc83c16111 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -1,3 +1,4 @@ +import { Metric, MetricOptions } from '@aws-cdk/aws-cloudwatch'; import { Duration } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnApi, CfnApiProps } from '../apigatewayv2.generated'; @@ -21,6 +22,51 @@ export interface IHttpApi extends IApi { */ readonly httpApiId: string; + /** + * Metric for the number of client-side errors captured in a given period. + * + * @default - sum over 5 minutes + */ + metricClientError(props?: MetricOptions): Metric; + + /** + * Metric for the number of server-side errors captured in a given period. + * + * @default - sum over 5 minutes + */ + metricServerError(props?: MetricOptions): Metric; + + /** + * Metric for the amount of data processed in bytes. + * + * @default - sum over 5 minutes + */ + metricDataProcessed(props?: MetricOptions): Metric; + + /** + * Metric for the total number API requests in a given period. + * + * @default - SampleCount over 5 minutes + */ + metricCount(props?: MetricOptions): Metric; + + /** + * Metric for the time between when API Gateway relays a request to the backend + * and when it receives a response from the backend. + * + * @default - no statistic + */ + metricIntegrationLatency(props?: MetricOptions): Metric; + + /** + * The time between when API Gateway receives a request from a client + * and when it returns a response to the client. + * The latency includes the integration latency and other API Gateway overhead. + * + * @default - no statistic + */ + metricLatency(props?: MetricOptions): Metric; + /** * Add a new VpcLink */ @@ -204,6 +250,30 @@ abstract class HttpApiBase extends ApiBase implements IHttpApi { // note that th public abstract readonly apiEndpoint: string; private vpcLinks: Record = {}; + public metricClientError(props?: MetricOptions): Metric { + return this.metric('4xx', { statistic: 'Sum', ...props }); + } + + public metricServerError(props?: MetricOptions): Metric { + return this.metric('5xx', { statistic: 'Sum', ...props }); + } + + public metricDataProcessed(props?: MetricOptions): Metric { + return this.metric('DataProcessed', { statistic: 'Sum', ...props }); + } + + public metricCount(props?: MetricOptions): Metric { + return this.metric('Count', { statistic: 'SampleCount', ...props }); + } + + public metricIntegrationLatency(props?: MetricOptions): Metric { + return this.metric('IntegrationLatency', props); + } + + public metricLatency(props?: MetricOptions): Metric { + return this.metric('Latency', props); + } + public addVpcLink(options: VpcLinkProps): VpcLink { const { vpcId } = options.vpc; if (vpcId in this.vpcLinks) { diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts index d6a5f96320e3b..3ad58eea4364b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts @@ -1,3 +1,4 @@ +import { Metric, MetricOptions } from '@aws-cdk/aws-cloudwatch'; import { Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnStage } from '../apigatewayv2.generated'; @@ -16,6 +17,51 @@ export interface IHttpStage extends IStage { * The API this stage is associated to. */ readonly api: IHttpApi; + + /** + * Metric for the number of client-side errors captured in a given period. + * + * @default - sum over 5 minutes + */ + metricClientError(props?: MetricOptions): Metric + + /** + * Metric for the number of server-side errors captured in a given period. + * + * @default - sum over 5 minutes + */ + metricServerError(props?: MetricOptions): Metric + + /** + * Metric for the amount of data processed in bytes. + * + * @default - sum over 5 minutes + */ + metricDataProcessed(props?: MetricOptions): Metric + + /** + * Metric for the total number API requests in a given period. + * + * @default - SampleCount over 5 minutes + */ + metricCount(props?: MetricOptions): Metric + + /** + * Metric for the time between when API Gateway relays a request to the backend + * and when it receives a response from the backend. + * + * @default - no statistic + */ + metricIntegrationLatency(props?: MetricOptions): Metric + + /** + * The time between when API Gateway receives a request from a client + * and when it returns a response to the client. + * The latency includes the integration latency and other API Gateway overhead. + * + * @default - no statistic + */ + metricLatency(props?: MetricOptions): Metric } /** @@ -49,16 +95,44 @@ export interface HttpStageAttributes extends StageAttributes { readonly api: IHttpApi; } +abstract class HttpStageBase extends StageBase implements IHttpStage { + public abstract readonly api: IHttpApi; + + public metricClientError(props?: MetricOptions): Metric { + return this.metric('4xx', { statistic: 'Sum', ...props }); + } + + public metricServerError(props?: MetricOptions): Metric { + return this.metric('5xx', { statistic: 'Sum', ...props }); + } + + public metricDataProcessed(props?: MetricOptions): Metric { + return this.metric('DataProcessed', { statistic: 'Sum', ...props }); + } + + public metricCount(props?: MetricOptions): Metric { + return this.metric('Count', { statistic: 'SampleCount', ...props }); + } + + public metricIntegrationLatency(props?: MetricOptions): Metric { + return this.metric('IntegrationLatency', props); + } + + public metricLatency(props?: MetricOptions): Metric { + return this.metric('Latency', props); + } +} + /** * Represents a stage where an instance of the API is deployed. * @resource AWS::ApiGatewayV2::Stage */ -export class HttpStage extends StageBase implements IHttpStage { +export class HttpStage extends HttpStageBase { /** * Import an existing stage into this CDK app. */ public static fromHttpStageAttributes(scope: Construct, id: string, attrs: HttpStageAttributes): IHttpStage { - class Import extends StageBase implements IHttpStage { + class Import extends HttpStageBase { protected readonly baseApi = attrs.api; public readonly stageName = attrs.stageName; public readonly api = attrs.api; diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index 29744be29408b..d53dfdede8aa5 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -76,7 +76,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts index 41e22f186eb01..25b0a5bca3189 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts @@ -148,7 +148,7 @@ describe('HttpApi', () => { const api = new HttpApi(stack, 'test-api', { createDefaultStage: false, }); - const metricName = '4xxError'; + const metricName = '4xx'; const statistic = 'Sum'; const apiId = api.apiId; @@ -185,6 +185,8 @@ describe('HttpApi', () => { expect(metric.dimensions).toEqual({ ApiId: apiId }); expect(metric.color).toEqual(color); } + const metricNames = metrics.map(m => m.metricName); + expect(metricNames).toEqual(['4xx', '5xx', 'DataProcessed', 'Latency', 'IntegrationLatency', 'Count']); }); test('Metrics from imported resource', () => { @@ -192,7 +194,7 @@ describe('HttpApi', () => { const stack = new Stack(); const apiId = 'importedId'; const api = HttpApi.fromHttpApiAttributes(stack, 'test-api', { httpApiId: apiId }); - const metricName = '4xxError'; + const metricName = '4xx'; const statistic = 'Sum'; // WHEN diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts index 63bfff4246b53..e3758183c68ff 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts @@ -67,7 +67,7 @@ describe('HttpStage', () => { const stage = new HttpStage(stack, 'Stage', { httpApi: api, }); - const metricName = '4xxError'; + const metricName = '4xx'; const statistic = 'Sum'; const apiId = api.apiId; @@ -113,5 +113,7 @@ describe('HttpStage', () => { }); expect(metric.color).toEqual(color); } + const metricNames = metrics.map(m => m.metricName); + expect(metricNames).toEqual(['4xx', '5xx', 'DataProcessed', 'Latency', 'IntegrationLatency', 'Count']); }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index abd158e0aee53..9baceaa0b44dd 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-appflow/package.json b/packages/@aws-cdk/aws-appflow/package.json index e0af29aadb2da..3e11ac670e7b5 100644 --- a/packages/@aws-cdk/aws-appflow/package.json +++ b/packages/@aws-cdk/aws-appflow/package.json @@ -70,7 +70,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-appintegrations/package.json b/packages/@aws-cdk/aws-appintegrations/package.json index ba009c4055982..70068025c4f6b 100644 --- a/packages/@aws-cdk/aws-appintegrations/package.json +++ b/packages/@aws-cdk/aws-appintegrations/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/assert-internal": "0.0.0", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json index 3cd9d3fe89eb8..e24079e01a95c 100644 --- a/packages/@aws-cdk/aws-applicationinsights/package.json +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-appmesh/README.md b/packages/@aws-cdk/aws-appmesh/README.md index 0adcc52901ba2..067575fb73ec0 100644 --- a/packages/@aws-cdk/aws-appmesh/README.md +++ b/packages/@aws-cdk/aws-appmesh/README.md @@ -149,15 +149,13 @@ const node = mesh.addVirtualNode('virtual-node', { }), listeners: [appmesh.VirtualNodeListener.httpNodeListener({ port: 8081, - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, interval: Duration.seconds(5), // minimum path: `/health-check-path`, - port: 8080, - protocol: Protocol.HTTP, timeout: Duration.seconds(2), // minimum unhealthyThreshold: 2, - }, + }), })], accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'), }); @@ -173,15 +171,13 @@ const node = new VirtualNode(this, 'node', { }), listeners: [appmesh.VirtualNodeListener.httpNodeListener({ port: 8080, - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, interval: Duration.seconds(5), // min path: '/ping', - port: 8080, - protocol: Protocol.HTTP, timeout: Duration.seconds(2), // min unhealthyThreshold: 2, - }, + }), timeout: { idle: cdk.Duration.seconds(5), }, @@ -207,15 +203,13 @@ const node = new VirtualNode(this, 'node', { }), listeners: [appmesh.VirtualNodeListener.httpNodeListener({ port: 8080, - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, interval: Duration.seconds(5), // min path: '/ping', - port: 8080, - protocol: Protocol.HTTP, timeout: Duration.seconds(2), // min unhealthyThreshold: 2, - }, + }), timeout: { idle: cdk.Duration.seconds(5), }, @@ -494,9 +488,9 @@ const gateway = new appmesh.VirtualGateway(stack, 'gateway', { mesh: mesh, listeners: [appmesh.VirtualGatewayListener.http({ port: 443, - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ interval: cdk.Duration.seconds(10), - }, + }), })], backendDefaults: { clientPolicy: appmesh.ClientPolicy.acmTrust({ @@ -517,9 +511,9 @@ const gateway = mesh.addVirtualGateway('gateway', { virtualGatewayName: 'virtualGateway', listeners: [appmesh.VirtualGatewayListener.http({ port: 443, - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ interval: cdk.Duration.seconds(10), - }, + }), })], }); ``` diff --git a/packages/@aws-cdk/aws-appmesh/lib/health-checks.ts b/packages/@aws-cdk/aws-appmesh/lib/health-checks.ts new file mode 100644 index 0000000000000..e783e2fe00602 --- /dev/null +++ b/packages/@aws-cdk/aws-appmesh/lib/health-checks.ts @@ -0,0 +1,189 @@ +import * as cdk from '@aws-cdk/core'; +import { CfnVirtualGateway, CfnVirtualNode } from './appmesh.generated'; +import { Protocol } from './shared-interfaces'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/** + * Properties used to define healthchecks. + */ +interface HealthCheckCommonOptions { + /** + * The number of consecutive successful health checks that must occur before declaring listener healthy. + * + * @default 2 + */ + readonly healthyThreshold?: number; + + /** + * The time period between each health check execution. + * + * @default Duration.seconds(5) + */ + readonly interval?: cdk.Duration; + + /** + * The amount of time to wait when receiving a response from the health check. + * + * @default Duration.seconds(2) + */ + readonly timeout?: cdk.Duration; + + /** + * The number of consecutive failed health checks that must occur before declaring a listener unhealthy. + * + * @default - 2 + */ + readonly unhealthyThreshold?: number; +} + +/** + * Properties used to define HTTP Based healthchecks. + */ +export interface HttpHealthCheckOptions extends HealthCheckCommonOptions { + /** + * The destination path for the health check request. + * + * @default / + */ + readonly path?: string; +} + +/** + * Properties used to define GRPC Based healthchecks. + */ +export interface GrpcHealthCheckOptions extends HealthCheckCommonOptions { } + +/** + * Properties used to define TCP Based healthchecks. + */ +export interface TcpHealthCheckOptions extends HealthCheckCommonOptions { } + +/** + * All Properties for Health Checks for mesh endpoints + */ +export interface HealthCheckConfig { + /** + * VirtualNode CFN configuration for Health Checks + * + * @default - no health checks + */ + readonly virtualNodeHealthCheck?: CfnVirtualNode.HealthCheckProperty; + + /** + * VirtualGateway CFN configuration for Health Checks + * + * @default - no health checks + */ + readonly virtualGatewayHealthCheck?: CfnVirtualGateway.VirtualGatewayHealthCheckPolicyProperty; +} + +/** + * Options used for creating the Health Check object + */ +export interface HealthCheckBindOptions { + /** + * Port for Health Check interface + * + * @default - no default port is provided + */ + readonly defaultPort?: number; +} + + +/** + * Contains static factory methods for creating health checks for different protocols + */ +export abstract class HealthCheck { + /** + * Construct a HTTP health check + */ + public static http(options: HttpHealthCheckOptions = {}): HealthCheck { + return new HealthCheckImpl(Protocol.HTTP, options.healthyThreshold, options.unhealthyThreshold, options.interval, options.timeout, options.path); + } + + /** + * Construct a HTTP2 health check + */ + public static http2(options: HttpHealthCheckOptions = {}): HealthCheck { + return new HealthCheckImpl(Protocol.HTTP2, options.healthyThreshold, options.unhealthyThreshold, options.interval, options.timeout, options.path); + } + + /** + * Construct a GRPC health check + */ + public static grpc(options: GrpcHealthCheckOptions = {}): HealthCheck { + return new HealthCheckImpl(Protocol.GRPC, options.healthyThreshold, options.unhealthyThreshold, options.interval, options.timeout); + } + + /** + * Construct a TCP health check + */ + public static tcp(options: TcpHealthCheckOptions = {}): HealthCheck { + return new HealthCheckImpl(Protocol.TCP, options.healthyThreshold, options.unhealthyThreshold, options.interval, options.timeout); + } + + /** + * Called when the AccessLog type is initialized. Can be used to enforce + * mutual exclusivity with future properties + */ + public abstract bind(scope: Construct, options: HealthCheckBindOptions): HealthCheckConfig; +} + +class HealthCheckImpl extends HealthCheck { + constructor( + private readonly protocol: Protocol, + private readonly healthyThreshold: number = 2, + private readonly unhealthyThreshold: number = 2, + private readonly interval: cdk.Duration = cdk.Duration.seconds(5), + private readonly timeout: cdk.Duration = cdk.Duration.seconds(2), + private readonly path?: string) { + super(); + if (healthyThreshold < 2 || healthyThreshold > 10) { + throw new Error('healthyThreshold must be between 2 and 10'); + } + + if (unhealthyThreshold < 2 || unhealthyThreshold > 10) { + throw new Error('unhealthyThreshold must be between 2 and 10'); + } + + if (interval.toMilliseconds() < 5000 || interval.toMilliseconds() > 300_000) { + throw new Error('interval must be between 5 seconds and 300 seconds'); + } + + if (timeout.toMilliseconds() < 2000 || timeout.toMilliseconds() > 60_000) { + throw new Error('timeout must be between 2 seconds and 60 seconds'); + } + + // Default to / for HTTP Health Checks + if (path === undefined && (protocol === Protocol.HTTP || protocol === Protocol.HTTP2)) { + this.path = '/'; + } + } + + public bind(_scope: Construct, options: HealthCheckBindOptions): HealthCheckConfig { + return { + virtualNodeHealthCheck: { + protocol: this.protocol, + healthyThreshold: this.healthyThreshold, + unhealthyThreshold: this.unhealthyThreshold, + intervalMillis: this.interval.toMilliseconds(), + timeoutMillis: this.timeout.toMilliseconds(), + path: this.path, + port: options.defaultPort, + }, + virtualGatewayHealthCheck: { + protocol: this.protocol, + healthyThreshold: this.healthyThreshold, + unhealthyThreshold: this.unhealthyThreshold, + intervalMillis: this.interval.toMilliseconds(), + timeoutMillis: this.timeout.toMilliseconds(), + path: this.path, + port: options.defaultPort, + }, + }; + } + +} diff --git a/packages/@aws-cdk/aws-appmesh/lib/index.ts b/packages/@aws-cdk/aws-appmesh/lib/index.ts index 1f5ca87def34d..4365a00da1279 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/index.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/index.ts @@ -16,3 +16,4 @@ export * from './virtual-gateway-listener'; export * from './gateway-route'; export * from './gateway-route-spec'; export * from './client-policy'; +export * from './health-checks'; diff --git a/packages/@aws-cdk/aws-appmesh/lib/private/utils.ts b/packages/@aws-cdk/aws-appmesh/lib/private/utils.ts index 7b5cfe620de1c..8b6bd42f5b27e 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/private/utils.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/private/utils.ts @@ -1,45 +1,3 @@ -import * as cdk from '@aws-cdk/core'; -import { CfnVirtualGateway, CfnVirtualNode } from '../appmesh.generated'; - -type AppMeshHealthCheck = CfnVirtualNode.HealthCheckProperty | CfnVirtualGateway.VirtualGatewayHealthCheckPolicyProperty - -/** - * Validates health check properties, throws an error if they are misconfigured. - * - * @param healthCheck Healthcheck property from a Virtual Node or Virtual Gateway - */ -export function validateHealthChecks(healthCheck: AppMeshHealthCheck) { - (Object.keys(healthCheck) as Array) - .filter((key) => - HEALTH_CHECK_PROPERTY_THRESHOLDS[key] && - typeof healthCheck[key] === 'number' && - !cdk.Token.isUnresolved(healthCheck[key]), - ).map((key) => { - const [min, max] = HEALTH_CHECK_PROPERTY_THRESHOLDS[key]!; - const value = healthCheck[key]!; - - if (value < min) { - throw new Error(`The value of '${key}' is below the minimum threshold (expected >=${min}, got ${value})`); - } - if (value > max) { - throw new Error(`The value of '${key}' is above the maximum threshold (expected <=${max}, got ${value})`); - } - }); -} - -/** - * Minimum and maximum thresholds for HeathCheck numeric properties - * - * @see https://docs.aws.amazon.com/app-mesh/latest/APIReference/API_HealthCheckPolicy.html - */ -const HEALTH_CHECK_PROPERTY_THRESHOLDS: {[key in (keyof AppMeshHealthCheck)]?: [number, number]} = { - healthyThreshold: [2, 10], - intervalMillis: [5000, 300000], - port: [1, 65535], - timeoutMillis: [2000, 60000], - unhealthyThreshold: [2, 10], -}; - /** * Generated Connection pool config */ diff --git a/packages/@aws-cdk/aws-appmesh/lib/route-spec.ts b/packages/@aws-cdk/aws-appmesh/lib/route-spec.ts index add785c02c286..be1da3c67af19 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/route-spec.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/route-spec.ts @@ -1,6 +1,6 @@ import * as cdk from '@aws-cdk/core'; import { CfnRoute } from './appmesh.generated'; -import { Protocol, HttpTimeout, GrpcTimeout, TcpTimeout } from './shared-interfaces'; +import { HttpTimeout, GrpcTimeout, Protocol, TcpTimeout } from './shared-interfaces'; import { IVirtualNode } from './virtual-node'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main diff --git a/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts b/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts index 5fb77b8cc4145..f1753ef7bb3b3 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts @@ -59,6 +59,8 @@ export interface TcpTimeout { /** * Enum of supported AppMesh protocols + * + * @deprecated not for use outside package */ export enum Protocol { HTTP = 'http', @@ -67,63 +69,6 @@ export enum Protocol { GRPC = 'grpc', } -/** - * Properties used to define healthchecks when creating virtual nodes. - * All values have a default if only specified as {} when creating. - * If property not set, then no healthchecks will be defined. - */ -export interface HealthCheck { - /** - * Number of successful attempts before considering the node UP - * - * @default 2 - */ - readonly healthyThreshold?: number; - - /** - * Interval in milliseconds to re-check - * - * @default 5 seconds - */ - readonly interval?: cdk.Duration; - - /** - * The path where the application expects any health-checks, this can also be the application path. - * - * @default / - */ - readonly path?: string; - - /** - * The TCP port number for the healthcheck - * - * @default - same as corresponding port mapping - */ - readonly port?: number; - - /** - * The protocol to use for the healthcheck, for convinience a const enum has been defined. - * Protocol.HTTP or Protocol.TCP - * - * @default - same as corresponding port mapping - */ - readonly protocol?: Protocol; - - /** - * Timeout in milli-seconds for the healthcheck to be considered a fail. - * - * @default 2 seconds - */ - readonly timeout?: cdk.Duration; - - /** - * Number of failed attempts before considering the node DOWN. - * - * @default 2 - */ - readonly unhealthyThreshold?: number; -} - /** * Represents the outlier detection for a listener. */ diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway-listener.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway-listener.ts index f4a083e3ea35e..d4b235a8dc4ed 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway-listener.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-gateway-listener.ts @@ -1,9 +1,8 @@ -import * as cdk from '@aws-cdk/core'; import { CfnVirtualGateway } from './appmesh.generated'; -import { validateHealthChecks, ConnectionPoolConfig } from './private/utils'; +import { HealthCheck } from './health-checks'; +import { ConnectionPoolConfig } from './private/utils'; import { GrpcConnectionPool, - HealthCheck, Http2ConnectionPool, HttpConnectionPool, Protocol, @@ -143,7 +142,7 @@ class VirtualGatewayListenerImpl extends VirtualGatewayListener { port: this.port, protocol: this.protocol, }, - healthCheck: this.healthCheck ? renderHealthCheck(this.healthCheck, this.protocol, this.port): undefined, + healthCheck: this.healthCheck?.bind(scope, { defaultPort: this.port }).virtualGatewayHealthCheck, tls: tlsConfig ? renderTls(tlsConfig) : undefined, connectionPool: this.connectionPool ? renderConnectionPool(this.connectionPool, this.protocol) : undefined, }, @@ -162,34 +161,6 @@ function renderTls(tlsCertificateConfig: TlsCertificateConfig): CfnVirtualGatewa }; } -function renderHealthCheck(hc: HealthCheck, listenerProtocol: Protocol, - listenerPort: number): CfnVirtualGateway.VirtualGatewayHealthCheckPolicyProperty { - - if (hc.protocol === Protocol.TCP) { - throw new Error('TCP health checks are not permitted for gateway listeners'); - } - - if (hc.protocol === Protocol.GRPC && hc.path) { - throw new Error('The path property cannot be set with Protocol.GRPC'); - } - - const protocol = hc.protocol? hc.protocol : listenerProtocol; - - const healthCheck: CfnVirtualGateway.VirtualGatewayHealthCheckPolicyProperty = { - healthyThreshold: hc.healthyThreshold || 2, - intervalMillis: (hc.interval || cdk.Duration.seconds(5)).toMilliseconds(), // min - path: hc.path || ((protocol === Protocol.HTTP || protocol === Protocol.HTTP2) ? '/' : undefined), - port: hc.port || listenerPort, - protocol: hc.protocol || listenerProtocol, - timeoutMillis: (hc.timeout || cdk.Duration.seconds(2)).toMilliseconds(), - unhealthyThreshold: hc.unhealthyThreshold || 2, - }; - - validateHealthChecks(healthCheck); - - return healthCheck; -} - function renderConnectionPool(connectionPool: ConnectionPoolConfig, listenerProtocol: Protocol): CfnVirtualGateway.VirtualGatewayConnectionPoolProperty { return ({ diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts index 7a046a138c3ca..6613be6ed2949 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts @@ -1,8 +1,8 @@ -import * as cdk from '@aws-cdk/core'; import { CfnVirtualNode } from './appmesh.generated'; -import { validateHealthChecks, ConnectionPoolConfig } from './private/utils'; +import { HealthCheck } from './health-checks'; +import { ConnectionPoolConfig } from './private/utils'; import { - GrpcConnectionPool, GrpcTimeout, HealthCheck, Http2ConnectionPool, HttpConnectionPool, + GrpcConnectionPool, GrpcTimeout, Http2ConnectionPool, HttpConnectionPool, HttpTimeout, OutlierDetection, Protocol, TcpConnectionPool, TcpTimeout, } from './shared-interfaces'; import { TlsCertificate, TlsCertificateConfig } from './tls-certificate'; @@ -185,7 +185,7 @@ class VirtualNodeListenerImpl extends VirtualNodeListener { port: this.port, protocol: this.protocol, }, - healthCheck: this.healthCheck ? this.renderHealthCheck(this.healthCheck) : undefined, + healthCheck: this.healthCheck?.bind(scope, { defaultPort: this.port }).virtualNodeHealthCheck, timeout: this.timeout ? this.renderTimeout(this.timeout) : undefined, tls: tlsConfig ? this.renderTls(tlsConfig) : undefined, outlierDetection: this.outlierDetection ? this.renderOutlierDetection(this.outlierDetection) : undefined, @@ -204,32 +204,6 @@ class VirtualNodeListenerImpl extends VirtualNodeListener { }; } - private renderHealthCheck(hc: HealthCheck): CfnVirtualNode.HealthCheckProperty | undefined { - if (hc === undefined) { return undefined; } - - if (hc.protocol === Protocol.TCP && hc.path) { - throw new Error('The path property cannot be set with Protocol.TCP'); - } - - if (hc.protocol === Protocol.GRPC && hc.path) { - throw new Error('The path property cannot be set with Protocol.GRPC'); - } - - const healthCheck: CfnVirtualNode.HealthCheckProperty = { - healthyThreshold: hc.healthyThreshold || 2, - intervalMillis: (hc.interval || cdk.Duration.seconds(5)).toMilliseconds(), // min - path: hc.path || (hc.protocol === Protocol.HTTP ? '/' : undefined), - port: hc.port || this.port, - protocol: hc.protocol || this.protocol, - timeoutMillis: (hc.timeout || cdk.Duration.seconds(2)).toMilliseconds(), - unhealthyThreshold: hc.unhealthyThreshold || 2, - }; - - validateHealthChecks(healthCheck); - - return healthCheck; - } - private renderTimeout(timeout: HttpTimeout): CfnVirtualNode.ListenerTimeoutProperty { return ({ [this.protocol]: { @@ -270,4 +244,3 @@ class VirtualNodeListenerImpl extends VirtualNodeListener { }); } } - diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index 9549425e15202..1b5c5e9a4b0b7 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -183,7 +183,8 @@ "duration-prop-type:@aws-cdk/aws-appmesh.TcpVirtualNodeListenerOptions.timeout", "duration-prop-type:@aws-cdk/aws-appmesh.GrpcRouteSpecOptions.timeout", "duration-prop-type:@aws-cdk/aws-appmesh.HttpRouteSpecOptions.timeout", - "duration-prop-type:@aws-cdk/aws-appmesh.TcpRouteSpecOptions.timeout" + "duration-prop-type:@aws-cdk/aws-appmesh.TcpRouteSpecOptions.timeout", + "no-unused-type:@aws-cdk/aws-appmesh.Protocol" ] }, "stability": "experimental", diff --git a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts index 68709def26f95..3e1b18a0073b1 100644 --- a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts +++ b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts @@ -31,10 +31,10 @@ const virtualService = new appmesh.VirtualService(stack, 'service', { const node = mesh.addVirtualNode('node', { serviceDiscovery: appmesh.ServiceDiscovery.dns(`node1.${namespace.namespaceName}`), listeners: [appmesh.VirtualNodeListener.http({ - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, path: '/check-path', - }, + }), })], backends: [appmesh.Backend.virtualService(virtualService)], }); @@ -67,15 +67,13 @@ router.addRoute('route-1', { const node2 = mesh.addVirtualNode('node2', { serviceDiscovery: appmesh.ServiceDiscovery.dns(`node2.${namespace.namespaceName}`), listeners: [appmesh.VirtualNodeListener.http({ - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, interval: cdk.Duration.seconds(5), path: '/check-path2', - port: 8080, - protocol: appmesh.Protocol.HTTP, timeout: cdk.Duration.seconds(2), unhealthyThreshold: 2, - }, + }), })], backendDefaults: { clientPolicy: appmesh.ClientPolicy.fileTrust({ @@ -93,15 +91,13 @@ const node2 = mesh.addVirtualNode('node2', { const node3 = mesh.addVirtualNode('node3', { serviceDiscovery: appmesh.ServiceDiscovery.dns(`node3.${namespace.namespaceName}`), listeners: [appmesh.VirtualNodeListener.http({ - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, interval: cdk.Duration.seconds(5), path: '/check-path3', - port: 8080, - protocol: appmesh.Protocol.HTTP, timeout: cdk.Duration.seconds(2), unhealthyThreshold: 2, - }, + }), })], backendDefaults: { clientPolicy: appmesh.ClientPolicy.fileTrust({ @@ -208,9 +204,9 @@ new appmesh.VirtualGateway(stack, 'gateway2', { mesh: mesh, listeners: [appmesh.VirtualGatewayListener.http({ port: 443, - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ interval: cdk.Duration.seconds(10), - }, + }), tlsCertificate: appmesh.TlsCertificate.file({ certificateChainPath: 'path/to/certChain', privateKeyPath: 'path/to/privateKey', diff --git a/packages/@aws-cdk/aws-appmesh/test/test.health-check.ts b/packages/@aws-cdk/aws-appmesh/test/test.health-check.ts index 1ba7dc425da07..57c6aa9ee1d61 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.health-check.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.health-check.ts @@ -22,14 +22,14 @@ export = { // WHEN const toThrow = (millis: number) => getNode(stack).addListener(appmesh.VirtualNodeListener.http2({ - healthCheck: { interval: cdk.Duration.millis(millis) }, + healthCheck: appmesh.HealthCheck.http2({ interval: cdk.Duration.millis(millis) }), })); // THEN test.doesNotThrow(() => toThrow(min)); test.doesNotThrow(() => toThrow(max)); - test.throws(() => toThrow(min - 1), /below the minimum threshold/); - test.throws(() => toThrow(max + 1), /above the maximum threshold/); + test.throws(() => toThrow(min - 1), /interval must be between 5 seconds and 300 seconds/); + test.throws(() => toThrow(max + 1), /interval must be between 5 seconds and 300 seconds/); test.done(); }, @@ -41,32 +41,14 @@ export = { // WHEN const toThrow = (millis: number) => getNode(stack).addListener(appmesh.VirtualNodeListener.http2({ - healthCheck: { timeout: cdk.Duration.millis(millis) }, + healthCheck: appmesh.HealthCheck.http2({ timeout: cdk.Duration.millis(millis) }), })); // THEN test.doesNotThrow(() => toThrow(min)); test.doesNotThrow(() => toThrow(max)); - test.throws(() => toThrow(min - 1), /below the minimum threshold/); - test.throws(() => toThrow(max + 1), /above the maximum threshold/); - - test.done(); - }, - 'port'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - const [min, max] = [1, 65535]; - - // WHEN - const toThrow = (port: number) => getNode(stack).addListener(appmesh.VirtualNodeListener.http({ - healthCheck: { port }, - })); - - // THEN - test.doesNotThrow(() => toThrow(min)); - test.doesNotThrow(() => toThrow(max)); - test.throws(() => toThrow(max + 1), /above the maximum threshold/); + test.throws(() => toThrow(min - 1), /timeout must be between 2 seconds and 60 seconds/); + test.throws(() => toThrow(max + 1), /timeout must be between 2 seconds and 60 seconds/); test.done(); }, @@ -78,14 +60,14 @@ export = { // WHEN const toThrow = (healthyThreshold: number) => getNode(stack).addListener(appmesh.VirtualNodeListener.http({ - healthCheck: { healthyThreshold }, + healthCheck: appmesh.HealthCheck.http({ healthyThreshold }), })); // THEN test.doesNotThrow(() => toThrow(min)); test.doesNotThrow(() => toThrow(max)); - test.throws(() => toThrow(min - 1), /below the minimum threshold/); - test.throws(() => toThrow(max + 1), /above the maximum threshold/); + test.throws(() => toThrow(min - 1), /healthyThreshold must be between 2 and 10/); + test.throws(() => toThrow(max + 1), /healthyThreshold must be between 2 and 10/); test.done(); }, @@ -97,53 +79,15 @@ export = { // WHEN const toThrow = (unhealthyThreshold: number) => getNode(stack).addListener(appmesh.VirtualNodeListener.http({ - healthCheck: { unhealthyThreshold }, + healthCheck: appmesh.HealthCheck.http({ unhealthyThreshold }), })); // THEN test.doesNotThrow(() => toThrow(min)); test.doesNotThrow(() => toThrow(max)); - test.throws(() => toThrow(min - 1), /below the minimum threshold/); - test.throws(() => toThrow(max + 1), /above the maximum threshold/); + test.throws(() => toThrow(min - 1), /unhealthyThreshold must be between 2 and 10/); + test.throws(() => toThrow(max + 1), /unhealthyThreshold must be between 2 and 10/); test.done(); }, - 'throws if path and Protocol.TCP'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const toThrow = (protocol: appmesh.Protocol) => getNode(stack).addListener(appmesh.VirtualNodeListener.http({ - healthCheck: { - protocol, - path: '/', - }, - })); - - // THEN - test.doesNotThrow(() => toThrow(appmesh.Protocol.HTTP)); - test.throws(() => toThrow(appmesh.Protocol.TCP), /The path property cannot be set with Protocol.TCP/); - - test.done(); - }, - - 'throws if path and Protocol.GRPC'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const toThrow = (protocol: appmesh.Protocol) => getNode(stack).addListener(appmesh.VirtualNodeListener.http({ - healthCheck: { - protocol, - path: '/', - }, - })); - - // THEN - test.doesNotThrow(() => toThrow(appmesh.Protocol.HTTP)); - test.throws(() => toThrow(appmesh.Protocol.GRPC), /The path property cannot be set with Protocol.GRPC/); - - test.done(); - }, - }; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-appmesh/test/test.mesh.ts b/packages/@aws-cdk/aws-appmesh/test/test.mesh.ts index ac71a80017d0a..dfecbc4292c88 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.mesh.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.mesh.ts @@ -213,13 +213,13 @@ export = { serviceDiscovery: appmesh.ServiceDiscovery.dns('test.domain.local'), listeners: [appmesh.VirtualNodeListener.http({ port: 8080, - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ healthyThreshold: 3, path: '/', interval: cdk.Duration.seconds(5), // min timeout: cdk.Duration.seconds(2), // min unhealthyThreshold: 2, - }, + }), })], }); diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts index 96d3c7cba9210..bafc0eccd6822 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-gateway.ts @@ -23,9 +23,9 @@ export = { mesh: mesh, listeners: [appmesh.VirtualGatewayListener.http({ port: 443, - healthCheck: { + healthCheck: appmesh.HealthCheck.http({ interval: cdk.Duration.seconds(10), - }, + }), })], }); @@ -33,9 +33,7 @@ export = { mesh: mesh, listeners: [appmesh.VirtualGatewayListener.http2({ port: 443, - healthCheck: { - interval: cdk.Duration.seconds(10), - }, + healthCheck: appmesh.HealthCheck.http2({ interval: cdk.Duration.seconds(10) }), })], }); @@ -115,8 +113,7 @@ export = { virtualGatewayName: 'test-gateway', listeners: [appmesh.VirtualGatewayListener.grpc({ port: 80, - healthCheck: { - }, + healthCheck: appmesh.HealthCheck.grpc(), })], mesh: mesh, accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'), diff --git a/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts b/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts index f143b0025c1db..b993309547ab8 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.virtual-node.ts @@ -163,7 +163,7 @@ export = { serviceDiscovery: appmesh.ServiceDiscovery.dns('test'), listeners: [appmesh.VirtualNodeListener.http2({ port: 80, - healthCheck: {}, + healthCheck: appmesh.HealthCheck.http2(), timeout: { idle: cdk.Duration.seconds(10) }, })], }); @@ -219,7 +219,9 @@ export = { node.addListener(appmesh.VirtualNodeListener.tcp({ port: 80, - healthCheck: { timeout: cdk.Duration.seconds(3) }, + healthCheck: appmesh.HealthCheck.tcp({ + timeout: cdk.Duration.seconds(3), + }), timeout: { idle: cdk.Duration.seconds(10) }, })); diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index d8520adbbe47b..027cf8919899e 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index fa472f4f66151..61ac81e9d385c 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index 66e3b89b38372..a1b280f9a6ac1 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "nodeunit-shim": "0.0.0", diff --git a/packages/@aws-cdk/aws-auditmanager/package.json b/packages/@aws-cdk/aws-auditmanager/package.json index c0e6420c302b2..ae2544821a2f8 100644 --- a/packages/@aws-cdk/aws-auditmanager/package.json +++ b/packages/@aws-cdk/aws-auditmanager/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index ab1d5ffb26f81..107f83ff25370 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -62,7 +62,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-ec2": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index ed81dec36bd55..3a35a0ac9f860 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts index de6ca78f9f45b..9fb5da7b46ce8 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts @@ -22,6 +22,12 @@ nodeunitShim({ }); expect(stack).toMatch({ + 'Parameters': { + 'SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter': { + 'Type': 'AWS::SSM::Parameter::Value', + 'Default': '/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2', + }, + }, 'Resources': { 'MyFleetInstanceSecurityGroup774E8234': { 'Type': 'AWS::EC2::SecurityGroup', @@ -83,7 +89,7 @@ nodeunitShim({ 'IamInstanceProfile': { 'Ref': 'MyFleetInstanceProfile70A58496', }, - 'ImageId': '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}', + 'ImageId': { 'Ref': 'SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter' }, 'InstanceType': 'm4.micro', 'SecurityGroups': [ { diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json index 36f25fecba0a8..af9c16803e320 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.amazonlinux2.expected.json @@ -423,7 +423,9 @@ "FleetLaunchConfig59F79D36": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "FleetInstanceProfileC6192A66" @@ -475,5 +477,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-metrics-collections.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-metrics-collections.expected.json new file mode 100644 index 0000000000000..ba27663a60ccd --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-metrics-collections.expected.json @@ -0,0 +1,661 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet3Subnet631C5E25": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3RouteTable98AE0E14": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3RouteTableAssociation427FE0C6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + } + } + }, + "VPCPublicSubnet3DefaultRouteA0D29D46": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet3EIPAD4BC883": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3NATGatewayD3048F5C": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet3EIPAD4BC883", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCPrivateSubnet3Subnet3EDCD457": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet3" + } + ] + } + }, + "VPCPrivateSubnet3RouteTable192186F8": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC/PrivateSubnet3" + } + ] + } + }, + "VPCPrivateSubnet3RouteTableAssociationC28D144E": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + } + }, + "VPCPrivateSubnet3DefaultRoute27F311AE": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "ASGInstanceSecurityGroup0525485D": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-cdk-asg-integ/ASG/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/ASG" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "ASGInstanceRoleE263A41B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/ASG" + } + ] + } + }, + "ASGInstanceProfile0A2834D7": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "ASGInstanceRoleE263A41B" + } + ] + } + }, + "ASGLaunchConfigC00AF12B": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "Properties": { + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "t2.micro", + "IamInstanceProfile": { + "Ref": "ASGInstanceProfile0A2834D7" + }, + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ASGInstanceSecurityGroup0525485D", + "GroupId" + ] + } + ], + "UserData": { + "Fn::Base64": "#!/bin/bash" + } + }, + "DependsOn": [ + "ASGInstanceRoleE263A41B" + ] + }, + "ASG46ED3070": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "MaxSize": "1", + "MinSize": "1", + "LaunchConfigurationName": { + "Ref": "ASGLaunchConfigC00AF12B" + }, + "MetricsCollection": [ + { + "Granularity": "1Minute" + }, + { + "Granularity": "1Minute", + "Metrics": [ + "GroupPendingInstances", + "GroupStandbyInstances", + "GroupTotalInstances" + ] + } + ], + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-cdk-asg-integ/ASG" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + }, + { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + ] + }, + "UpdatePolicy": { + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-classic-loadbalancer.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-classic-loadbalancer.expected.json index 8bcafeca92ca7..5882016a8f8b2 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-classic-loadbalancer.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-classic-loadbalancer.expected.json @@ -603,7 +603,9 @@ "FleetLaunchConfig59F79D36": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "FleetInstanceProfileC6192A66" @@ -747,5 +749,11 @@ "VPCPublicSubnet3DefaultRouteA0D29D46" ] } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json index 9dcd5257d05ef..34f240a76559d 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.asg-w-elbv2.expected.json @@ -444,7 +444,9 @@ "FleetLaunchConfig59F79D36": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "FleetInstanceProfileC6192A66" @@ -675,5 +677,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.custom-scaling.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.custom-scaling.expected.json index bcc87632a5c29..21457d1ea78e6 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.custom-scaling.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.custom-scaling.expected.json @@ -423,7 +423,9 @@ "FleetLaunchConfig59F79D36": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "FleetInstanceProfileC6192A66" @@ -509,5 +511,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.external-role.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.external-role.expected.json index 8a810d98515fe..49196dcc8ba93 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.external-role.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.external-role.expected.json @@ -576,7 +576,9 @@ "ASGLaunchConfigC00AF12B": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "ASGInstanceProfile0A2834D7" @@ -630,5 +632,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/integ.spot-instances.expected.json b/packages/@aws-cdk/aws-autoscaling/test/integ.spot-instances.expected.json index bc7b8de6da282..709737be069fe 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/integ.spot-instances.expected.json +++ b/packages/@aws-cdk/aws-autoscaling/test/integ.spot-instances.expected.json @@ -423,7 +423,9 @@ "FleetLaunchConfig59F79D36": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "FleetInstanceProfileC6192A66" @@ -475,5 +477,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts b/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts index b1043837a4bd4..e5044af33543e 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts @@ -96,6 +96,12 @@ nodeunitShim({ }, }, }, + Parameters: { + SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: '/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2', + }, + }, }, MatchStyle.SUPERSET); test.done(); diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index 42e6a1ba3d1e2..902f17dfd8ab0 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 276e60337083d..366c7a20f72f8 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index ce61d402738ee..0ab890c0c9546 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts index 244b323981002..dd18be3f1496c 100644 --- a/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts +++ b/packages/@aws-cdk/aws-batch/test/compute-environment.test.ts @@ -214,7 +214,9 @@ describe('Batch Compute Evironment', () => { AllocationStrategy: batch.AllocationStrategy.BEST_FIT, DesiredvCpus: props.computeResources.desiredvCpus, Ec2KeyPair: props.computeResources.ec2KeyPair, - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, InstanceRole: { 'Fn::GetAtt': [ props.computeResources.instanceRole ? 'InstanceProfile' : '', diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index 9b815b05bcb1c..4b57842332145 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index 9b32bee762a17..9a66b67e105fd 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index d6cad44f201c4..6dea1a924c2aa 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json index f9c66a46718f7..02dd246c76e47 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json @@ -27,12 +27,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.75", + "@types/aws-lambda": "^8.10.76", "@types/sinon": "^9.0.11", "cdk-build-tools": "0.0.0", "aws-sdk": "^2.596.0", "aws-sdk-mock": "^5.1.0", - "eslint": "^7.24.0", + "eslint": "^7.26.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", @@ -40,8 +40,8 @@ "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", - "sinon": "^9.0.2", + "sinon": "^9.2.4", "nock": "^13.0.11", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.6" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index 38edda79af06c..b601342654213 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index e06f96810a69a..b1a327c77f19a 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index caf58cf835c7b..deef42d133ecd 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-codecommit": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index c9d816c42a815..9433981c2133a 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -72,7 +72,7 @@ "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "@types/aws-lambda": "^8.10.75", + "@types/aws-lambda": "^8.10.76", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index 0eb6533292ea7..92688f9d2ce76 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -69,7 +69,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-ec2": "0.0.0", "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts index dee1f9cbbce50..a45bc0ce6db97 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/experimental/edge-function.ts @@ -3,13 +3,11 @@ import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; -// hack, as this is not exported by the Lambda module -import { calculateFunctionHash } from '@aws-cdk/aws-lambda/lib/function-hash'; import * as ssm from '@aws-cdk/aws-ssm'; import { - ConstructNode, + CfnResource, ConstructNode, CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, - Resource, Stack, Stage, Token, + Lazy, Resource, Stack, Stage, Token, } from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -157,17 +155,18 @@ export class EdgeFunction extends Resource implements lambda.IVersion { addEdgeLambdaToRoleTrustStatement(edgeFunction.role!); // Store the current version's ARN to be retrieved by the cross region reader below. + const version = edgeFunction.currentVersion; new ssm.StringParameter(edgeFunction, 'Parameter', { parameterName, - stringValue: edgeFunction.currentVersion.edgeArn, + stringValue: version.edgeArn, }); - const edgeArn = this.createCrossRegionArnReader(parameterNamePrefix, parameterName, edgeFunction); + const edgeArn = this.createCrossRegionArnReader(parameterNamePrefix, parameterName, version); return { edgeFunction, edgeArn }; } - private createCrossRegionArnReader(parameterNamePrefix: string, parameterName: string, edgeFunction: lambda.Function): string { + private createCrossRegionArnReader(parameterNamePrefix: string, parameterName: string, version: lambda.Version): string { // Prefix of the parameter ARN that applies to all EdgeFunctions. // This is necessary because the `CustomResourceProvider` is a singleton, and the `policyStatement` // must work for multiple EdgeFunctions. @@ -196,7 +195,15 @@ export class EdgeFunction extends Resource implements lambda.IVersion { Region: EdgeFunction.EDGE_REGION, ParameterName: parameterName, // This is used to determine when the function has changed, to refresh the ARN from the custom resource. - RefreshToken: calculateFunctionHash(edgeFunction), + // + // Use the logical id of the function version. Whenever a function version changes, the logical id must be + // changed for it to take effect - a good candidate for RefreshToken. + RefreshToken: Lazy.uncachedString({ + produce: () => { + const cfn = version.node.defaultChild as CfnResource; + return this.stack.resolve(cfn.logicalId); + }, + }), }, }); diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index f6b849b16d9d6..7ae097b628922 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json index 6da7e8717d61f..d95e038c2c890 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.distribution-lambda-cross-region.expected.json @@ -12,7 +12,7 @@ }, "Region": "us-east-1", "ParameterName": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda", - "RefreshToken": "4412ddb0ae449da20173ca211c51fddc" + "RefreshToken": "LambdaCurrentVersionDF706F6A97fb843e9bd06fcd2bb15eeace80e13e" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -138,7 +138,7 @@ }, "Region": "us-east-1", "ParameterName": "/cdk/EdgeFunctionArn/eu-west-1/integ-distribution-lambda-cross-region/Lambda2", - "RefreshToken": "8f81ceb404ac454f09648e62822d9ca9" + "RefreshToken": "Lambda2CurrentVersion72012B74b9eef8becb98501bc795baca3c6169c4" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index fb85a7d313d28..506513079f999 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 1a8155c377a52..881ee54c2656f 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -62,7 +62,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-ec2": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts b/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts index eaa48446672f9..296400ee7f910 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts @@ -12,14 +12,14 @@ export interface IMetric { /** * Turn this metric object into an alarm configuration * - * @deprecated Use `toMetricsConfig()` instead. + * @deprecated Use `toMetricConfig()` instead. */ toAlarmConfig(): MetricAlarmConfig; /** * Turn this metric object into a graph configuration * - * @deprecated Use `toMetricsConfig()` instead. + * @deprecated Use `toMetricConfig()` instead. */ toGraphConfig(): MetricGraphConfig; } @@ -27,6 +27,8 @@ export interface IMetric { /** * Metric dimension * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-dimension.html + * */ export interface Dimension { /** diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts b/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts index 0590a592da502..3bb3d512c86d0 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts @@ -216,7 +216,9 @@ export class Metric implements IMetric { if (periodSec !== 1 && periodSec !== 5 && periodSec !== 10 && periodSec !== 30 && periodSec % 60 !== 0) { throw new Error(`'period' must be 1, 5, 10, 30, or a multiple of 60 seconds, received ${periodSec}`); } - + if (props.dimensions) { + this.validateDimensions(props.dimensions); + } this.dimensions = props.dimensions; this.namespace = props.namespace; this.metricName = props.metricName; @@ -395,6 +397,26 @@ export class Metric implements IMetric { return list; } + + private validateDimensions(dims: DimensionHash): void { + var dimsArray = Object.keys(dims); + if (dimsArray?.length > 10) { + throw new Error(`The maximum number of dimensions is 10, received ${dimsArray.length}`); + } + + dimsArray.map(key => { + if (dims[key] === undefined || dims[key] === null) { + throw new Error(`Dimension value of '${dims[key]}' is invalid`); + }; + if (key.length < 1 || key.length > 255) { + throw new Error(`Dimension name must be at least 1 and no more than 255 characters; received ${key}`); + }; + + if (dims[key].length < 1 || dims[key].length > 255) { + throw new Error(`Dimension value must be at least 1 and no more than 255 characters; received ${dims[key]}`); + }; + }); + } } function asString(x?: unknown): string | undefined { diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts b/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts index 18e1840e35cb6..e1dc9230e1404 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts @@ -51,4 +51,77 @@ export = { test.done(); }, + + 'cannot use null dimension value'(test: Test) { + test.throws(() => { + new Metric({ + namespace: 'Test', + metricName: 'ACount', + period: cdk.Duration.minutes(10), + dimensions: { + DimensionWithNull: null, + }, + }); + }, /Dimension value of 'null' is invalid/); + + test.done(); + }, + + 'cannot use undefined dimension value'(test: Test) { + test.throws(() => { + new Metric({ + namespace: 'Test', + metricName: 'ACount', + period: cdk.Duration.minutes(10), + dimensions: { + DimensionWithUndefined: undefined, + }, + }); + }, /Dimension value of 'undefined' is invalid/); + + test.done(); + }, + + 'cannot use long dimension values'(test: Test) { + const arr = new Array(256); + const invalidDimensionValue = arr.fill('A', 0).join(''); + + test.throws(() => { + new Metric({ + namespace: 'Test', + metricName: 'ACount', + period: cdk.Duration.minutes(10), + dimensions: { + DimensionWithLongValue: invalidDimensionValue, + }, + }); + }, `Dimension value must be at least 1 and no more than 255 characters; received ${invalidDimensionValue}`); + + test.done(); + }, + + 'throws error when there are more than 10 dimensions'(test: Test) { + test.throws(() => { + new Metric({ + namespace: 'Test', + metricName: 'ACount', + period: cdk.Duration.minutes(10), + dimensions: { + dimensionA: 'value1', + dimensionB: 'value2', + dimensionC: 'value3', + dimensionD: 'value4', + dimensionE: 'value5', + dimensionF: 'value6', + dimensionG: 'value7', + dimensionH: 'value8', + dimensionI: 'value9', + dimensionJ: 'value10', + dimensionK: 'value11', + }, + } ); + }, /The maximum number of dimensions is 10, received 11/); + + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-codeartifact/package.json b/packages/@aws-cdk/aws-codeartifact/package.json index 39ce84acc4fc8..96a62e0b4e801 100644 --- a/packages/@aws-cdk/aws-codeartifact/package.json +++ b/packages/@aws-cdk/aws-codeartifact/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json b/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json index 189c58b36eec0..c5ae20b9ac145 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json +++ b/packages/@aws-cdk/aws-codedeploy/test/server/integ.deployment-group.expected.json @@ -639,7 +639,9 @@ "ASGLaunchConfigC00AF12B": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "m5.large", "IamInstanceProfile": { "Ref": "ASGInstanceProfile0A2834D7" @@ -875,5 +877,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index fb4b7bcb99502..8eac7b8a18af5 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json index c7425d062bb66..d7e411d99ee3f 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/package.json +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index 2b3e9898e502f..48b7c111f56f6 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -66,7 +66,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-cloudtrail": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@types/lodash": "^4.14.168", diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index 25433aafc2fb1..0c52c95657acc 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -76,7 +76,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index a12f7e2c59a39..c7206144de2c6 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index 6c95638dabd34..d216451a1caa0 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index 36d0ab1d74c4d..1d220f65881e4 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index ce488cf3cf622..0ac87ea6ba50b 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/punycode": "^2.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-customerprofiles/package.json b/packages/@aws-cdk/aws-customerprofiles/package.json index 6810e4d06baec..17b6f9fb26612 100644 --- a/packages/@aws-cdk/aws-customerprofiles/package.json +++ b/packages/@aws-cdk/aws-customerprofiles/package.json @@ -76,7 +76,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert-internal": "0.0.0", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0" diff --git a/packages/@aws-cdk/aws-databrew/package.json b/packages/@aws-cdk/aws-databrew/package.json index 8d03f1f617354..eeba7990834a7 100644 --- a/packages/@aws-cdk/aws-databrew/package.json +++ b/packages/@aws-cdk/aws-databrew/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index 0f7e2bf5178b6..3549f8fea9a9f 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-datasync/package.json b/packages/@aws-cdk/aws-datasync/package.json index fa500952c61e4..a1d18fa6f8aa3 100644 --- a/packages/@aws-cdk/aws-datasync/package.json +++ b/packages/@aws-cdk/aws-datasync/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index 05cb93bd5b813..69ace1acbc1a5 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index 558ae44370663..717be699c22ad 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-devopsguru/package.json b/packages/@aws-cdk/aws-devopsguru/package.json index 35ab77f636371..cdab8bcc65c6a 100644 --- a/packages/@aws-cdk/aws-devopsguru/package.json +++ b/packages/@aws-cdk/aws-devopsguru/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index 02f733ad3dced..df966366462c8 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index 10213c995e8f2..5037eaacd8232 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index 0e5010acb620b..476adefb9dbf3 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-docdb/README.md b/packages/@aws-cdk/aws-docdb/README.md index 7121a5dee71bb..fb1c4eeb270ee 100644 --- a/packages/@aws-cdk/aws-docdb/README.md +++ b/packages/@aws-cdk/aws-docdb/README.md @@ -50,6 +50,16 @@ attributes: const writeAddress = cluster.clusterEndpoint.socketAddress; // "HOSTNAME:PORT" ``` +If you have existing security groups you would like to add to the cluster, use the `addSecurityGroups` method. Security +groups added in this way will not be managed by the `Connections` object of the cluster. + +```ts +const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { + vpc, +}); +cluster.addSecurityGroups(securityGroup); +``` + ## Rotating credentials When the master password is generated and stored in AWS Secrets Manager, it can be rotated automatically: diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts index 71df7275d5cba..f90e976db8798 100644 --- a/packages/@aws-cdk/aws-docdb/lib/cluster.ts +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -283,6 +283,11 @@ export class DatabaseCluster extends DatabaseClusterBase { */ public readonly secret?: secretsmanager.ISecret; + /** + * The underlying CloudFormation resource for a database cluster. + */ + private readonly cluster: CfnDBCluster; + /** * The VPC where the DB subnet group is created. */ @@ -348,7 +353,7 @@ export class DatabaseCluster extends DatabaseClusterBase { } // Create the DocDB cluster - const cluster = new CfnDBCluster(this, 'Resource', { + this.cluster = new CfnDBCluster(this, 'Resource', { // Basic engineVersion: props.engineVersion, dbClusterIdentifier: props.dbClusterName, @@ -370,16 +375,16 @@ export class DatabaseCluster extends DatabaseClusterBase { storageEncrypted, }); - cluster.applyRemovalPolicy(props.removalPolicy, { + this.cluster.applyRemovalPolicy(props.removalPolicy, { applyToUpdateReplacePolicy: true, }); - this.clusterIdentifier = cluster.ref; - this.clusterResourceIdentifier = cluster.attrClusterResourceId; + this.clusterIdentifier = this.cluster.ref; + this.clusterResourceIdentifier = this.cluster.attrClusterResourceId; - const port = Token.asNumber(cluster.attrPort); - this.clusterEndpoint = new Endpoint(cluster.attrEndpoint, port); - this.clusterReadEndpoint = new Endpoint(cluster.attrReadEndpoint, port); + const port = Token.asNumber(this.cluster.attrPort); + this.clusterEndpoint = new Endpoint(this.cluster.attrEndpoint, port); + this.clusterReadEndpoint = new Endpoint(this.cluster.attrReadEndpoint, port); if (secret) { this.secret = secret.attach(this); @@ -399,7 +404,7 @@ export class DatabaseCluster extends DatabaseClusterBase { const instance = new CfnDBInstance(this, `Instance${instanceIndex}`, { // Link to cluster - dbClusterIdentifier: cluster.ref, + dbClusterIdentifier: this.cluster.ref, dbInstanceIdentifier: instanceIdentifier, // Instance properties dbInstanceClass: databaseInstanceType(props.instanceType), @@ -467,6 +472,17 @@ export class DatabaseCluster extends DatabaseClusterBase { target: this, }); } + + /** + * Adds security groups to this cluster. + * @param securityGroups The security groups to add. + */ + public addSecurityGroups(...securityGroups: ec2.ISecurityGroup[]): void { + if (this.cluster.vpcSecurityGroupIds === undefined) { + this.cluster.vpcSecurityGroupIds = []; + } + this.cluster.vpcSecurityGroupIds.push(...securityGroups.map(sg => sg.securityGroupId)); + } } /** diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index 35959d2409d1e..128a7f4904fbc 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index b503cb1f14cbd..1dd057fa29653 100644 --- a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -1,4 +1,4 @@ -import { expect as expectCDK, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; +import { expect as expectCDK, haveResource, ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; @@ -725,6 +725,29 @@ describe('DatabaseCluster', () => { expect(addMultiUserRotation).toThrow(); }); + test('adds security groups', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new DatabaseCluster(stack, 'Database', { + vpc, + masterUser: { + username: 'admin', + }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.SMALL), + }); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { + vpc, + }); + + // WHEN + cluster.addSecurityGroups(securityGroup); + + // THEN + expectCDK(stack).to(haveResource('AWS::DocDB::DBCluster', { + VpcSecurityGroupIds: arrayWith(stack.resolve(securityGroup.securityGroupId)), + })); + }); }); function testStack() { diff --git a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json index 540b1f6ea76a7..c9d9180d2d772 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json @@ -29,7 +29,7 @@ "devDependencies": { "aws-sdk": "^2.596.0", "aws-sdk-mock": "^5.1.0", - "eslint": "^7.24.0", + "eslint": "^7.26.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 2fc69c8c4d53c..db9b6b51ea3f5 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -71,8 +71,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.75", - "@types/jest": "^26.0.22", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", @@ -82,7 +82,7 @@ "jest": "^26.6.3", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^26.5.4", + "ts-jest": "^26.5.6", "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 6916b91eb21f6..5b6e630634d10 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -71,8 +71,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.75", - "@types/jest": "^26.0.22", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts index 8d080b37bc442..f774cf9aaa3d8 100644 --- a/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/bastion-host.test.ts @@ -97,7 +97,9 @@ nodeunitShim({ // THEN expect(stack).to(haveResource('AWS::EC2::Instance', { - ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter', + }, })); test.done(); @@ -115,7 +117,9 @@ nodeunitShim({ // THEN expect(stack).to(haveResource('AWS::EC2::Instance', { - ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmarm64gp2C96584B6F00A464EAD1953AFF4B05118Parameter', + }, })); test.done(); diff --git a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host-arm-support.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host-arm-support.expected.json index d9ed4091ca53a..81f4ae3377d40 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host-arm-support.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host-arm-support.expected.json @@ -611,7 +611,9 @@ "IamInstanceProfile": { "Ref": "BastionHostInstanceProfile770FCA07" }, - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmarm64gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t4g.nano", "SecurityGroupIds": [ { @@ -647,5 +649,11 @@ "Ref": "BastionHost30F9ED05" } } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmarm64gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json index cd3d2bc2e705b..4943873897e75 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.bastion-host.expected.json @@ -611,7 +611,9 @@ "IamInstanceProfile": { "Ref": "BastionHostInstanceProfile770FCA07" }, - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.nano", "SecurityGroupIds": [ { @@ -647,5 +649,11 @@ "Ref": "BastionHost30F9ED05" } } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance-init.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.instance-init.expected.json index f99bfc4a6b96b..2b736d3961b4c 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance-init.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance-init.expected.json @@ -137,7 +137,9 @@ "IamInstanceProfile": { "Ref": "Instance2InstanceProfile582F915C" }, - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "SecurityGroupIds": [ { @@ -300,6 +302,10 @@ } }, "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + }, "AssetParametersf8a1af398dac2fad92eeea4fb7620be1c4f504e23e3bfcd859fbb5744187930bS3Bucket597083AB": { "Type": "String", "Description": "S3 bucket for asset \"f8a1af398dac2fad92eeea4fb7620be1c4f504e23e3bfcd859fbb5744187930b\"" @@ -313,4 +319,4 @@ "Description": "Artifact hash for asset \"f8a1af398dac2fad92eeea4fb7620be1c4f504e23e3bfcd859fbb5744187930b\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance-multipart-userdata.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.instance-multipart-userdata.expected.json index c5a08cce4530a..371a30e7456f6 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance-multipart-userdata.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance-multipart-userdata.expected.json @@ -620,7 +620,9 @@ "IamInstanceProfile": { "Ref": "InstanceInstanceProfileAB5AEF02" }, - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.nano", "SecurityGroupIds": [ { @@ -682,5 +684,11 @@ "InstanceInstanceRoleE9785DE5" ] } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json b/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json index e433b190ade9a..957af9c0f453e 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json +++ b/packages/@aws-cdk/aws-ec2/test/integ.instance.expected.json @@ -616,7 +616,9 @@ "IamInstanceProfile": { "Ref": "InstanceInstanceProfileAB5AEF02" }, - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.nano", "SecurityGroupIds": [ { @@ -644,5 +646,11 @@ "InstanceInstanceRoleE9785DE5" ] } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts b/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts index 389d5ef55155c..4d033a0cad78c 100644 --- a/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/launch-template.test.ts @@ -3,6 +3,7 @@ import { expect as expectCDK, haveResource, haveResourceLike, + stringLike, } from '@aws-cdk/assert-internal'; import { CfnInstanceProfile, @@ -157,7 +158,9 @@ describe('LaunchTemplate', () => { // THEN expectCDK(stack).to(haveResourceLike('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { - ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}', + ImageId: { + Ref: stringLike('SsmParameterValueawsserviceamiamazonlinuxlatestamznami*Parameter'), + }, }, })); expect(template.osType).toBe(OperatingSystemType.LINUX); @@ -173,7 +176,9 @@ describe('LaunchTemplate', () => { // THEN expectCDK(stack).to(haveResourceLike('AWS::EC2::LaunchTemplate', { LaunchTemplateData: { - ImageId: '{{resolve:ssm:/aws/service/ami-windows-latest/Windows_Server-2019-English-Full-Base}}', + ImageId: { + Ref: stringLike('SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishFullBase*Parameter'), + }, }, })); expect(template.osType).toBe(OperatingSystemType.WINDOWS); diff --git a/packages/@aws-cdk/aws-ecr-assets/README.md b/packages/@aws-cdk/aws-ecr-assets/README.md index a08ed95a9d676..a2d7ff50d8773 100644 --- a/packages/@aws-cdk/aws-ecr-assets/README.md +++ b/packages/@aws-cdk/aws-ecr-assets/README.md @@ -69,6 +69,38 @@ const asset = new DockerImageAsset(this, 'MyBuildImage', { }) ``` +## Publishing images to ECR repositories + +`DockerImageAsset` is designed for seamless build & consumption of image assets by CDK code deployed to multiple environments +through the CDK CLI or through CI/CD workflows. To that end, the ECR repository behind this construct is controlled by the AWS CDK. +The mechanics of where these images are published and how are intentionally kept as an implementation detail, and the construct +does not support customizations such as specifying the ECR repository name or tags. + +If you are looking for a way to _publish_ image assets to an ECR repository in your control, you should consider using +[wchaws/cdk-ecr-deployment], which is able to replicate an image asset from the CDK-controlled ECR repository to a repository of +your choice. + +Here an example from the [wchaws/cdk-ecr-deployment] project: + +```ts +import * as ecrdeploy from 'cdk-ecr-deployment'; + +const image = new DockerImageAsset(this, 'CDKDockerImage', { + directory: path.join(__dirname, 'docker'), +}); + +new ecrdeploy.ECRDeployment(this, 'DeployDockerImage', { + src: new ecrdeploy.DockerImageName(image.imageUri), + dest: new ecrdeploy.DockerImageName(`${cdk.Aws.ACCOUNT_ID}.dkr.ecr.us-west-2.amazonaws.com/test:nginx`), +}); +``` + +⚠️ Please note that this is a 3rd-party construct library and is not officially supported by AWS. +You are welcome to +1 [this GitHub issue](https://github.com/aws/aws-cdk/issues/12597) if you would like to see +native support for this use-case in the AWS CDK. + +[wchaws/cdk-ecr-deployment]: https://github.com/wchaws/cdk-ecr-deployment + ## Pull Permissions Depending on the consumer of your image asset, you will need to make sure diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index 140045075756c..055015cc313cd 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -63,7 +63,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/proxyquire": "^1.3.28", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecr/.gitignore b/packages/@aws-cdk/aws-ecr/.gitignore index 018c65919d67c..266c0684c6844 100644 --- a/packages/@aws-cdk/aws-ecr/.gitignore +++ b/packages/@aws-cdk/aws-ecr/.gitignore @@ -14,5 +14,6 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js -junit.xml \ No newline at end of file +junit.xml diff --git a/packages/@aws-cdk/aws-ecr/.npmignore b/packages/@aws-cdk/aws-ecr/.npmignore index a94c531529866..94b89531c7268 100644 --- a/packages/@aws-cdk/aws-ecr/.npmignore +++ b/packages/@aws-cdk/aws-ecr/.npmignore @@ -19,8 +19,9 @@ dist tsconfig.json .eslintrc.js +jest.config.js # exclude cdk artifacts **/cdk.out junit.xml -test/ \ No newline at end of file +test/ diff --git a/packages/@aws-cdk/aws-ecr/jest.config.js b/packages/@aws-cdk/aws-ecr/jest.config.js new file mode 100644 index 0000000000000..07a010c639ba8 --- /dev/null +++ b/packages/@aws-cdk/aws-ecr/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + ...baseConfig.coverageThreshold.global, + branches: 70, + }, + }, +}; diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index c81a4e29cf6b2..6fcba59ace523 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -55,7 +55,8 @@ "cloudformation": "AWS::ECR", "env": { "AWSLINT_BASE_CONSTRUCT": true - } + }, + "jest": true }, "nyc": { "lines": 78, @@ -74,13 +75,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/nodeunit": "^0.0.31", + "@aws-cdk/assert-internal": "0.0.0", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "pkglint": "0.0.0" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecr/test/test.auth-token.ts b/packages/@aws-cdk/aws-ecr/test/auth-token.test.ts similarity index 71% rename from packages/@aws-cdk/aws-ecr/test/test.auth-token.ts rename to packages/@aws-cdk/aws-ecr/test/auth-token.test.ts index a76e0274b7cee..f9be93b1e15d0 100644 --- a/packages/@aws-cdk/aws-ecr/test/test.auth-token.ts +++ b/packages/@aws-cdk/aws-ecr/test/auth-token.test.ts @@ -1,11 +1,10 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; +import { expect as expectCDK, haveResourceLike } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { AuthorizationToken, PublicGalleryAuthorizationToken } from '../lib'; -export = { - 'AuthorizationToken.grantRead()'(test: Test) { +describe('auth-token', () => { + test('AuthorizationToken.grantRead()', () => { // GIVEN const stack = new Stack(); const user = new iam.User(stack, 'User'); @@ -14,7 +13,7 @@ export = { AuthorizationToken.grantRead(user); // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expectCDK(stack).to(haveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -25,11 +24,9 @@ export = { ], }, })); + }); - test.done(); - }, - - 'PublicGalleryAuthorizationToken.grantRead()'(test: Test) { + test('PublicGalleryAuthorizationToken.grantRead()', () => { // GIVEN const stack = new Stack(); const user = new iam.User(stack, 'User'); @@ -38,7 +35,7 @@ export = { PublicGalleryAuthorizationToken.grantRead(user); // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { + expectCDK(stack).to(haveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -52,8 +49,5 @@ export = { ], }, })); - - test.done(); - }, - -}; \ No newline at end of file + }); +}); diff --git a/packages/@aws-cdk/aws-ecr/test/test.repository.ts b/packages/@aws-cdk/aws-ecr/test/repository.test.ts similarity index 71% rename from packages/@aws-cdk/aws-ecr/test/test.repository.ts rename to packages/@aws-cdk/aws-ecr/test/repository.test.ts index e90f56fb13303..5c7efecca1380 100644 --- a/packages/@aws-cdk/aws-ecr/test/test.repository.ts +++ b/packages/@aws-cdk/aws-ecr/test/repository.test.ts @@ -1,13 +1,12 @@ -import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; +import { expect as expectCDK, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as ecr from '../lib'; /* eslint-disable quote-props */ -export = { - 'construct repository'(test: Test) { +describe('repository', () => { + test('construct repository', () => { // GIVEN const stack = new cdk.Stack(); @@ -15,7 +14,7 @@ export = { new ecr.Repository(stack, 'Repo'); // THEN - expect(stack).toMatch({ + expectCDK(stack).toMatch({ Resources: { Repo02AC86CF: { Type: 'AWS::ECR::Repository', @@ -24,11 +23,9 @@ export = { }, }, }); + }); - test.done(); - }, - - 'repository creation with imageScanOnPush'(test: Test) { + test('repository creation with imageScanOnPush', () => { // GIVEN const stack = new cdk.Stack(); @@ -36,15 +33,14 @@ export = { new ecr.Repository(stack, 'Repo', { imageScanOnPush: true }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { ImageScanningConfiguration: { ScanOnPush: true, }, })); - test.done(); - }, + }); - 'tag-based lifecycle policy'(test: Test) { + test('tag-based lifecycle policy', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -53,31 +49,26 @@ export = { repo.addLifecycleRule({ tagPrefixList: ['abc'], maxImageCount: 1 }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"tagged","tagPrefixList":["abc"],"countType":"imageCountMoreThan","countNumber":1},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - - 'image tag mutability can be set'(test: Test) { + test('image tag mutability can be set', () => { // GIVEN const stack = new cdk.Stack(); new ecr.Repository(stack, 'Repo', { imageTagMutability: ecr.TagMutability.IMMUTABLE }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { ImageTagMutability: 'IMMUTABLE', })); + }); - test.done(); - }, - - 'add day-based lifecycle policy'(test: Test) { + test('add day-based lifecycle policy', () => { // GIVEN const stack = new cdk.Stack(); @@ -88,17 +79,15 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"sinceImagePushed","countNumber":5,"countUnit":"days"},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - 'add count-based lifecycle policy'(test: Test) { + test('add count-based lifecycle policy', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -109,17 +98,15 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - 'mixing numbered and unnumbered rules'(test: Test) { + test('mixing numbered and unnumbered rules', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -129,17 +116,15 @@ export = { repo.addLifecycleRule({ rulePriority: 10, tagStatus: ecr.TagStatus.TAGGED, tagPrefixList: ['b'], maxImageCount: 5 }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":10,"selection":{"tagStatus":"tagged","tagPrefixList":["b"],"countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}},{"rulePriority":11,"selection":{"tagStatus":"tagged","tagPrefixList":["a"],"countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - 'tagstatus Any is automatically sorted to the back'(test: Test) { + test('tagstatus Any is automatically sorted to the back', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -149,17 +134,15 @@ export = { repo.addLifecycleRule({ tagStatus: ecr.TagStatus.TAGGED, tagPrefixList: ['important'], maxImageCount: 999 }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { LifecyclePolicy: { // eslint-disable-next-line max-len LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"tagged","tagPrefixList":["important"],"countType":"imageCountMoreThan","countNumber":999},"action":{"type":"expire"}},{"rulePriority":2,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":5},"action":{"type":"expire"}}]}', }, })); + }); - test.done(); - }, - - 'lifecycle rules can be added upon initialization'(test: Test) { + test('lifecycle rules can be added upon initialization', () => { // GIVEN const stack = new cdk.Stack(); @@ -171,16 +154,15 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { 'LifecyclePolicy': { // eslint-disable-next-line max-len 'LifecyclePolicyText': '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":3},"action":{"type":"expire"}}]}', }, })); - test.done(); - }, + }); - 'calculate repository URI'(test: Test) { + test('calculate repository URI', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -190,7 +172,7 @@ export = { // THEN const arnSplit = { 'Fn::Split': [':', { 'Fn::GetAtt': ['Repo02AC86CF', 'Arn'] }] }; - test.deepEqual(stack.resolve(uri), { + expectCDK(stack.resolve(uri)).toMatch({ 'Fn::Join': ['', [ { 'Fn::Select': [4, arnSplit] }, '.dkr.ecr.', @@ -201,11 +183,9 @@ export = { { Ref: 'Repo02AC86CF' }, ]], }); + }); - test.done(); - }, - - 'import with concrete arn'(test: Test) { + test('import with concrete arn', () => { // GIVEN const stack = new cdk.Stack(); @@ -213,24 +193,21 @@ export = { const repo2 = ecr.Repository.fromRepositoryArn(stack, 'repo', 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo'); // THEN - test.deepEqual(stack.resolve(repo2.repositoryArn), 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo'); - test.deepEqual(stack.resolve(repo2.repositoryName), 'foo/bar/foo/fooo'); + expect(stack.resolve(repo2.repositoryArn)).toBe('arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo'); + expect(stack.resolve(repo2.repositoryName)).toBe('foo/bar/foo/fooo'); + }); - test.done(); - }, - - 'fails if importing with token arn and no name'(test: Test) { + test('fails if importing with token arn and no name', () => { // GIVEN const stack = new cdk.Stack(); // WHEN/THEN - test.throws(() => ecr.Repository.fromRepositoryArn(stack, 'arn', cdk.Fn.getAtt('Boom', 'Boom').toString()), - /\"repositoryArn\" is a late-bound value, and therefore \"repositoryName\" is required\. Use \`fromRepositoryAttributes\` instead/); - - test.done(); - }, + expect(() => { + ecr.Repository.fromRepositoryArn(stack, 'arn', cdk.Fn.getAtt('Boom', 'Boom').toString()); + }).toThrow(/\"repositoryArn\" is a late-bound value, and therefore \"repositoryName\" is required\. Use \`fromRepositoryAttributes\` instead/); + }); - 'import with token arn and repository name (see awslabs/aws-cdk#1232)'(test: Test) { + test('import with token arn and repository name (see awslabs/aws-cdk#1232)', () => { // GIVEN const stack = new cdk.Stack(); @@ -241,12 +218,11 @@ export = { }); // THEN - test.deepEqual(stack.resolve(repo.repositoryArn), { 'Fn::GetAtt': ['Boom', 'Arn'] }); - test.deepEqual(stack.resolve(repo.repositoryName), { 'Fn::GetAtt': ['Boom', 'Name'] }); - test.done(); - }, + expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ 'Fn::GetAtt': ['Boom', 'Arn'] }); + expectCDK(stack.resolve(repo.repositoryName)).toMatch({ 'Fn::GetAtt': ['Boom', 'Name'] }); + }); - 'import only with a repository name (arn is deduced)'(test: Test) { + test('import only with a repository name (arn is deduced)', () => { // GIVEN const stack = new cdk.Stack(); @@ -254,7 +230,7 @@ export = { const repo = ecr.Repository.fromRepositoryName(stack, 'just-name', 'my-repo'); // THEN - test.deepEqual(stack.resolve(repo.repositoryArn), { + expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ 'Fn::Join': ['', [ 'arn:', { Ref: 'AWS::Partition' }, @@ -265,11 +241,10 @@ export = { ':repository/my-repo', ]], }); - test.deepEqual(stack.resolve(repo.repositoryName), 'my-repo'); - test.done(); - }, + expect(stack.resolve(repo.repositoryName)).toBe('my-repo'); + }); - 'arnForLocalRepository can be used to render an ARN for a local repository'(test: Test) { + test('arnForLocalRepository can be used to render an ARN for a local repository', () => { // GIVEN const stack = new cdk.Stack(); const repoName = cdk.Fn.getAtt('Boom', 'Name').toString(); @@ -281,8 +256,8 @@ export = { }); // THEN - test.deepEqual(stack.resolve(repo.repositoryName), { 'Fn::GetAtt': ['Boom', 'Name'] }); - test.deepEqual(stack.resolve(repo.repositoryArn), { + expectCDK(stack.resolve(repo.repositoryName)).toMatch({ 'Fn::GetAtt': ['Boom', 'Name'] }); + expectCDK(stack.resolve(repo.repositoryArn)).toMatch({ 'Fn::Join': ['', [ 'arn:', { Ref: 'AWS::Partition' }, @@ -294,10 +269,9 @@ export = { { 'Fn::GetAtt': ['Boom', 'Name'] }, ]], }); - test.done(); - }, + }); - 'resource policy'(test: Test) { + test('resource policy', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -309,7 +283,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { RepositoryPolicyText: { Statement: [ { @@ -321,11 +295,9 @@ export = { Version: '2012-10-17', }, })); + }); - test.done(); - }, - - 'fails if repository policy has no actions'(test: Test) { + test('fails if repository policy has no actions', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'my-stack'); @@ -338,11 +310,10 @@ export = { })); // THEN - test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); - test.done(); - }, + expect(() => app.synth()).toThrow(/A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + }); - 'fails if repository policy has no IAM principals'(test: Test) { + test('fails if repository policy has no IAM principals', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'my-stack'); @@ -355,12 +326,11 @@ export = { })); // THEN - test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); - test.done(); - }, + expect(() => app.synth()).toThrow(/A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + }); - 'events': { - 'onImagePushed without imageTag creates the correct event'(test: Test) { + describe('events', () => { + test('onImagePushed without imageTag creates the correct event', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -370,7 +340,7 @@ export = { }, }); - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -390,10 +360,9 @@ export = { }, 'State': 'ENABLED', })); + }); - test.done(); - }, - 'onImageScanCompleted without imageTags creates the correct event'(test: Test) { + test('onImageScanCompleted without imageTags creates the correct event', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -403,7 +372,7 @@ export = { }, }); - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -421,11 +390,9 @@ export = { }, 'State': 'ENABLED', })); + }); - test.done(); - - }, - 'onImageScanCompleted with one imageTag creates the correct event'(test: Test) { + test('onImageScanCompleted with one imageTag creates the correct event', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -436,7 +403,7 @@ export = { }, }); - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -457,11 +424,9 @@ export = { }, 'State': 'ENABLED', })); + }); - test.done(); - - }, - 'onImageScanCompleted with multiple imageTags creates the correct event'(test: Test) { + test('onImageScanCompleted with multiple imageTags creates the correct event', () => { const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'Repo'); @@ -472,7 +437,7 @@ export = { }, }); - expect(stack).to(haveResourceLike('AWS::Events::Rule', { + expectCDK(stack).to(haveResourceLike('AWS::Events::Rule', { 'EventPattern': { 'source': [ 'aws.ecr', @@ -495,12 +460,9 @@ export = { }, 'State': 'ENABLED', })); + }); - test.done(); - - }, - - 'removal policy is "Retain" by default'(test: Test) { + test('removal policy is "Retain" by default', () => { // GIVEN const stack = new cdk.Stack(); @@ -508,14 +470,13 @@ export = { new ecr.Repository(stack, 'Repo'); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { 'Type': 'AWS::ECR::Repository', 'DeletionPolicy': 'Retain', }, ResourcePart.CompleteDefinition)); - test.done(); - }, + }); - '"Delete" removal policy can be set explicitly'(test: Test) { + test('"Delete" removal policy can be set explicitly', () => { // GIVEN const stack = new cdk.Stack(); @@ -525,14 +486,13 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { 'Type': 'AWS::ECR::Repository', 'DeletionPolicy': 'Delete', }, ResourcePart.CompleteDefinition)); - test.done(); - }, + }); - 'grant adds appropriate resource-*'(test: Test) { + test('grant adds appropriate resource-*', () => { // GIVEN const stack = new cdk.Stack(); const repo = new ecr.Repository(stack, 'TestHarnessRepo'); @@ -541,7 +501,7 @@ export = { repo.grantPull(new iam.AnyPrincipal()); // THEN - expect(stack).to(haveResource('AWS::ECR::Repository', { + expectCDK(stack).to(haveResource('AWS::ECR::Repository', { 'RepositoryPolicyText': { 'Statement': [ { @@ -557,8 +517,6 @@ export = { 'Version': '2012-10-17', }, })); - - test.done(); - }, - }, -}; + }); + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json index 83100fb8404f1..0412778adb2e8 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.multiple-application-load-balanced-ecs-service.expected.json @@ -505,7 +505,9 @@ "ClusterDefaultAutoScalingGroupLaunchConfig81EA5466": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "ClusterDefaultAutoScalingGroupInstanceProfile2BB4FE55" @@ -1158,6 +1160,12 @@ ] } }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } + }, "Outputs": { "myServiceLoadBalancerDNS3A083E9F": { "Value": { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json index cb276afd853f3..e3afaddbeb7c6 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.lit.expected.json @@ -325,7 +325,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -882,5 +884,11 @@ ] } } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index 06b37fd118b70..7f0338ed3ff18 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -153,6 +153,22 @@ cluster.addCapacity('bottlerocket-asg', { }); ``` +### ARM64 (Graviton) Instances + +To launch instances with ARM64 hardware, you can use the Amazon ECS-optimized +Amazon Linux 2 (arm64) AMI. Based on Amazon Linux 2, this AMI is recommended +for use when launching your EC2 instances that are powered by Arm-based AWS +Graviton Processors. + +```ts +cluster.addCapacity('graviton-cluster', { + minCapacity: 2, + instanceType: new ec2.InstanceType('c6g.large'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.ARM), +}); + +``` + ### Spot Instances To add spot instances into the cluster, you must specify the `spotPrice` in the `ecs.AddCapacityOptions` and optionally enable the `spotInstanceDraining` property. @@ -525,7 +541,7 @@ const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef'); taskDefinition.addContainer('TheContainer', { image: ecs.ContainerImage.fromAsset(path.resolve(__dirname, '..', 'eventhandler-image')), memoryLimitMiB: 256, - logging: new ecs.AwsLogDriver({ streamPrefix: 'EventDemo' }) + logging: new ecs.AwsLogDriver({ streamPrefix: 'EventDemo', mode: AwsLogDriverMode.NON_BLOCKING }) }); // An Rule that describes the event trigger (in this case a scheduled run) diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index 41fe61e299276..e51756cf7fa91 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -637,7 +637,7 @@ export abstract class BaseService extends Resource } /** - * This method returns the CloudWatch metric for this clusters memory utilization. + * This method returns the CloudWatch metric for this service's memory utilization. * * @default average over 5 minutes */ @@ -646,7 +646,7 @@ export abstract class BaseService extends Resource } /** - * This method returns the CloudWatch metric for this clusters CPU utilization. + * This method returns the CloudWatch metric for this service's CPU utilization. * * @default average over 5 minutes */ diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index c60fc9f4b1dee..a65efaa83e17e 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -466,7 +466,7 @@ export enum WindowsOptimizedVersion { /* * TODO:v2.0.0 * * remove `export` keyword - * * remove @depracted + * * remove @deprecated */ /** * The properties that define which ECS-optimized AMI is used. diff --git a/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts b/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts index 705c4ed7fcb72..e6da02b29797e 100644 --- a/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts @@ -8,6 +8,23 @@ import { removeEmpty } from './utils'; // eslint-disable-next-line import { Construct as CoreConstruct } from '@aws-cdk/core'; +/** + * awslogs provides two modes for delivering messages from the container to the log driver + */ +export enum AwsLogDriverMode { + + /** + * (default) direct, blocking delivery from container to driver. + */ + BLOCKING = 'blocking', + + /** + * The non-blocking message delivery mode prevents applications from blocking due to logging back pressure. + * Applications are likely to fail in unexpected ways when STDERR or STDOUT streams block. + */ + NON_BLOCKING = 'non-blocking' +} + /** * Specifies the awslogs log driver configuration options. */ @@ -62,6 +79,13 @@ export interface AwsLogDriverProps { * @default - No multiline matching. */ readonly multilinePattern?: string; + + /** + * The delivery mode of log messages from the container to awslogs. + * + * @default - AwsLogDriverMode.BLOCKING + */ + readonly mode?: AwsLogDriverMode; } /** @@ -106,6 +130,7 @@ export class AwsLogDriver extends LogDriver { 'awslogs-region': Stack.of(containerDefinition).region, 'awslogs-datetime-format': this.props.datetimeFormat, 'awslogs-multiline-pattern': this.props.multilinePattern, + 'mode': this.props.mode, }), }; } diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index 70207412b9604..c427a0fd4870c 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-s3-deployment": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@types/nodeunit": "^0.0.31", diff --git a/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts b/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts index d0aec83a2e36d..8a802ac72014b 100644 --- a/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/aws-log-driver.test.ts @@ -25,6 +25,7 @@ nodeunitShim({ logRetention: logs.RetentionDays.ONE_MONTH, multilinePattern: 'pattern', streamPrefix: 'hello', + mode: ecs.AwsLogDriverMode.NON_BLOCKING, }), }); @@ -44,6 +45,7 @@ nodeunitShim({ 'awslogs-region': { Ref: 'AWS::Region' }, 'awslogs-datetime-format': 'format', 'awslogs-multiline-pattern': 'pattern', + 'mode': 'non-blocking', }, }, }, diff --git a/packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts similarity index 90% rename from packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts rename to packages/@aws-cdk/aws-ecs/test/cluster.test.ts index 8b4af8a955e58..713338284e57b 100644 --- a/packages/@aws-cdk/aws-ecs/test/ecs-cluster.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/cluster.test.ts @@ -39,7 +39,9 @@ nodeunitShim({ })); expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, InstanceType: 't2.micro', IamInstanceProfile: { Ref: 'EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3', @@ -208,7 +210,9 @@ nodeunitShim({ })); expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, InstanceType: 't2.micro', IamInstanceProfile: { Ref: 'EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3', @@ -570,7 +574,9 @@ nodeunitShim({ })); expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, InstanceType: 't2.micro', IamInstanceProfile: { Ref: 'EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3', @@ -764,7 +770,9 @@ nodeunitShim({ // THEN expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/windows_server/2019/english/full/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiwindowsserver2019englishfullrecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, InstanceType: 't2.micro', IamInstanceProfile: { Ref: 'EcsClusterWindowsAutoScalingGroupInstanceProfile65DFA6BB', @@ -818,10 +826,21 @@ nodeunitShim({ }); // THEN + const assembly = app.synth(); + const template = assembly.getStackByName(stack.stackName).template; expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, })); + test.deepEqual(template.Parameters, { + SsmParameterValueawsserviceecsoptimizedamiamazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: '/aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended/image_id', + }, + }); + test.done(); }, @@ -848,7 +867,8 @@ nodeunitShim({ 'allows specifying windows image'(test: Test) { // GIVEN - const stack = new cdk.Stack(); + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); const vpc = new ec2.Vpc(stack, 'MyVpc', {}); const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); @@ -860,9 +880,14 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/windows_server/2019/english/full/recommended/image_id}}', - })); + const assembly = app.synth(); + const template = assembly.getStackByName(stack.stackName).template; + test.deepEqual(template.Parameters, { + SsmParameterValueawsserviceecsoptimizedamiwindowsserver2019englishfullrecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: '/aws/service/ecs/optimized-ami/windows_server/2019/english/full/recommended/image_id', + }, + }); test.done(); }, @@ -965,6 +990,17 @@ nodeunitShim({ test.done(); }, + 'allows returning the correct image for linux 2 for EcsOptimizedImage with ARM hardware'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + test.equal(ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.ARM).getImage(stack).osType, + ec2.OperatingSystemType.LINUX); + + test.done(); + }, + + 'allows returning the correct image for windows for EcsOptimizedImage'(test: Test) { // GIVEN const stack = new cdk.Stack(); @@ -981,7 +1017,8 @@ nodeunitShim({ 'allows specifying special HW AMI Type v2'(test: Test) { // GIVEN - const stack = new cdk.Stack(); + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); const vpc = new ec2.Vpc(stack, 'MyVpc', {}); const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); @@ -991,16 +1028,28 @@ nodeunitShim({ }); // THEN + const assembly = app.synth(); + const template = assembly.getStackByName(stack.stackName).template; expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, })); + test.deepEqual(template.Parameters, { + SsmParameterValueawsserviceecsoptimizedamiamazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: '/aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended/image_id', + }, + }); + test.done(); }, 'allows specifying Amazon Linux v1 AMI'(test: Test) { // GIVEN - const stack = new cdk.Stack(); + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); const vpc = new ec2.Vpc(stack, 'MyVpc', {}); const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); @@ -1010,16 +1059,28 @@ nodeunitShim({ }); // THEN + const assembly = app.synth(); + const template = assembly.getStackByName(stack.stackName).template; expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinuxrecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, })); + test.deepEqual(template.Parameters, { + SsmParameterValueawsserviceecsoptimizedamiamazonlinuxrecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: '/aws/service/ecs/optimized-ami/amazon-linux/recommended/image_id', + }, + }); + test.done(); }, 'allows specifying windows image v2'(test: Test) { // GIVEN - const stack = new cdk.Stack(); + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); const vpc = new ec2.Vpc(stack, 'MyVpc', {}); const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); @@ -1029,9 +1090,14 @@ nodeunitShim({ }); // THEN - expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/windows_server/2019/english/full/recommended/image_id}}', - })); + const assembly = app.synth(); + const template = assembly.getStackByName(stack.stackName).template; + test.deepEqual(template.Parameters, { + SsmParameterValueawsserviceecsoptimizedamiwindowsserver2019englishfullrecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: '/aws/service/ecs/optimized-ami/windows_server/2019/english/full/recommended/image_id', + }, + }); test.done(); }, @@ -1355,7 +1421,9 @@ nodeunitShim({ })); expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, InstanceType: 't2.micro', AssociatePublicIpAddress: true, IamInstanceProfile: { @@ -1497,19 +1565,30 @@ nodeunitShim({ 'BottleRocketImage() returns correct AMI'(test: Test) { // GIVEN - const stack = new cdk.Stack(); + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); // WHEN - const machineImageConfig = new ecs.BottleRocketImage().getImage(stack); + new ecs.BottleRocketImage().getImage(stack); // THEN - test.equal(stack.resolve(machineImageConfig.imageId), '{{resolve:ssm:/aws/service/bottlerocket/aws-ecs-1/x86_64/latest/image_id}}'); + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template.Parameters; + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsservicebottlerocketawsecs') && + (v as any).Default.includes('/bottlerocket/'), + ), 'Bottlerocket AMI should be in ssm parameters'); + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsservicebottlerocketawsecs') && + (v as any).Default.includes('/aws-ecs-1/'), + ), 'ecs variant should be in ssm parameters'); test.done(); }, 'cluster capacity with bottlerocket AMI'(test: Test) { // GIVEN - const stack = new cdk.Stack(); + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'test'); const cluster = new ecs.Cluster(stack, 'EcsCluster'); cluster.addCapacity('bottlerocket-asg', { @@ -1521,7 +1600,9 @@ nodeunitShim({ expect(stack).to(haveResource('AWS::ECS::Cluster')); expect(stack).to(haveResource('AWS::AutoScaling::AutoScalingGroup')); expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/bottlerocket/aws-ecs-1/x86_64/latest/image_id}}', + ImageId: { + Ref: 'SsmParameterValueawsservicebottlerocketawsecs1x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter', + }, UserData: { 'Fn::Base64': { 'Fn::Join': [ @@ -1589,7 +1670,7 @@ nodeunitShim({ Tags: [ { Key: 'Name', - Value: 'Default/EcsCluster/bottlerocket-asg', + Value: 'test/EcsCluster/bottlerocket-asg', }, ], }), diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json index 5931bfbe6125d..2e5eed7f911c6 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json @@ -484,7 +484,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -966,5 +968,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json index 68ecfe2a87661..616a80172092e 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.bottlerocket.expected.json @@ -478,7 +478,9 @@ "EcsClusterbottlerocketasgLaunchConfig644AD24C": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/bottlerocket/aws-ecs-1/x86_64/latest/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsservicebottlerocketawsecs1x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "c5.large", "IamInstanceProfile": { "Ref": "EcsClusterbottlerocketasgInstanceProfile22A89B9D" @@ -830,5 +832,11 @@ "EcsClusterbottlerocketasgLifecycleHookDrainHookRoleDE4D94EB" ] } + }, + "Parameters": { + "SsmParameterValueawsservicebottlerocketawsecs1x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/bottlerocket/aws-ecs-1/x86_64/latest/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json index 51ec3e18fb52f..77ccc9c6c36c6 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json @@ -505,7 +505,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -1005,6 +1007,12 @@ } } }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } + }, "Outputs": { "LoadBalancerDNS": { "Value": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json index 6808def866ea1..da866432d8539 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.cloudmap-container-port.expected.json @@ -305,7 +305,9 @@ "FargateClustercapacityLaunchConfig9B95CCB7": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.micro", "IamInstanceProfile": { "Ref": "FargateClustercapacityInstanceProfile8294296C" @@ -796,5 +798,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json index 406021932bd02..c309c8a70f249 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json @@ -497,7 +497,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -1330,6 +1332,10 @@ } }, "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", "Description": "S3 bucket for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" @@ -1379,4 +1385,4 @@ "Description": "Artifact hash for asset \"872561bf078edd1685d50c9ff821cdd60d2b2ddfb0013c4087e79bf2bb50724d\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json index 358ccdcee2969..e863d75fa16fb 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.firelens-s3-config.expected.json @@ -484,7 +484,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -908,7 +910,9 @@ }, "Type": "fluentbit" }, - "Image": "{{resolve:ssm:/aws/service/aws-for-fluent-bit/2.1.0}}", + "Image": { + "Ref": "SsmParameterValueawsserviceawsforfluentbit210C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "LogConfiguration": { "LogDriver": "awslogs", "Options": { @@ -1160,6 +1164,10 @@ } }, "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + }, "AssetParameters2ca891b3a73a4a36630bba20580e3390a104d2ac9ff1f22a6bcadf575f8a5a61S3Bucket4E939944": { "Type": "String", "Description": "S3 bucket for asset \"2ca891b3a73a4a36630bba20580e3390a104d2ac9ff1f22a6bcadf575f8a5a61\"" @@ -1171,6 +1179,10 @@ "AssetParameters2ca891b3a73a4a36630bba20580e3390a104d2ac9ff1f22a6bcadf575f8a5a61ArtifactHashB4EEDAF3": { "Type": "String", "Description": "Artifact hash for asset \"2ca891b3a73a4a36630bba20580e3390a104d2ac9ff1f22a6bcadf575f8a5a61\"" + }, + "SsmParameterValueawsserviceawsforfluentbit210C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/aws-for-fluent-bit/2.1.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json new file mode 100644 index 0000000000000..8529dea9b1171 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.expected.json @@ -0,0 +1,848 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "EcsCluster97242B84": { + "Type": "AWS::ECS::Cluster" + }, + "EcsClustergravitonclusterInstanceSecurityGroup0187E9BB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-ecs-integ/EcsCluster/graviton-cluster/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "EcsClustergravitonclusterInstanceRole0D0E0F94": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "ec2.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, + "EcsClustergravitonclusterInstanceRoleDefaultPolicyB89DB33F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecs:DeregisterContainerInstance", + "ecs:RegisterContainerInstance", + "ecs:Submit*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + }, + { + "Action": [ + "ecs:Poll", + "ecs:StartTelemetrySession" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecs:DiscoverPollEndpoint", + "ecr:GetAuthorizationToken", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EcsClustergravitonclusterInstanceRoleDefaultPolicyB89DB33F", + "Roles": [ + { + "Ref": "EcsClustergravitonclusterInstanceRole0D0E0F94" + } + ] + } + }, + "EcsClustergravitonclusterInstanceProfileD1BBFAAE": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "EcsClustergravitonclusterInstanceRole0D0E0F94" + } + ] + } + }, + "EcsClustergravitonclusterLaunchConfig64183B57": { + "Type": "AWS::AutoScaling::LaunchConfiguration", + "Properties": { + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "c6g.large", + "IamInstanceProfile": { + "Ref": "EcsClustergravitonclusterInstanceProfileD1BBFAAE" + }, + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "EcsClustergravitonclusterInstanceSecurityGroup0187E9BB", + "GroupId" + ] + } + ], + "UserData": { + "Fn::Base64": { + "Fn::Join": [ + "", + [ + "#!/bin/bash\necho ECS_CLUSTER=", + { + "Ref": "EcsCluster97242B84" + }, + " >> /etc/ecs/ecs.config\nsudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP\nsudo service iptables save\necho ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config" + ] + ] + } + } + }, + "DependsOn": [ + "EcsClustergravitonclusterInstanceRoleDefaultPolicyB89DB33F", + "EcsClustergravitonclusterInstanceRole0D0E0F94" + ] + }, + "EcsClustergravitonclusterASG869F3168": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "MaxSize": "2", + "MinSize": "2", + "LaunchConfigurationName": { + "Ref": "EcsClustergravitonclusterLaunchConfig64183B57" + }, + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + }, + "UpdatePolicy": { + "AutoScalingReplacingUpdate": { + "WillReplace": true + }, + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + }, + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, + "EcsClustergravitonclusterDrainECSHookFunctionServiceRoleDefaultPolicy1563DC6B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:DescribeInstances", + "ec2:DescribeInstanceAttribute", + "ec2:DescribeInstanceStatus", + "ec2:DescribeHosts" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "autoscaling:CompleteLifecycleAction", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":autoscaling:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":autoScalingGroup:*:autoScalingGroupName/", + { + "Ref": "EcsClustergravitonclusterASG869F3168" + } + ] + ] + } + }, + { + "Action": [ + "ecs:DescribeContainerInstances", + "ecs:DescribeTasks" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecs:ListContainerInstances", + "ecs:SubmitContainerStateChange", + "ecs:SubmitTaskStateChange" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + }, + { + "Action": [ + "ecs:UpdateContainerInstancesState", + "ecs:ListTasks" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "EcsCluster97242B84", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EcsClustergravitonclusterDrainECSHookFunctionServiceRoleDefaultPolicy1563DC6B", + "Roles": [ + { + "Ref": "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764" + } + ] + } + }, + "EcsClustergravitonclusterDrainECSHookFunctionB606E681": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(event))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(event))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n \n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n \n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n \n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + }, + "Role": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", + "Arn" + ] + }, + "Environment": { + "Variables": { + "CLUSTER": { + "Ref": "EcsCluster97242B84" + } + } + }, + "Handler": "index.lambda_handler", + "Runtime": "python3.6", + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ], + "Timeout": 310 + }, + "DependsOn": [ + "EcsClustergravitonclusterDrainECSHookFunctionServiceRoleDefaultPolicy1563DC6B", + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764" + ] + }, + "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionB606E681", + "Arn" + ] + }, + "Principal": "sns.amazonaws.com", + "SourceArn": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + } + } + }, + "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43": { + "Type": "AWS::SNS::Subscription", + "Properties": { + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + }, + "Endpoint": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionB606E681", + "Arn" + ] + } + } + }, + "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "autoscaling.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, + "EcsClustergravitonclusterLifecycleHookDrainHookRoleDefaultPolicy516A6DA7": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "EcsClustergravitonclusterLifecycleHookDrainHookRoleDefaultPolicy516A6DA7", + "Roles": [ + { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD" + } + ] + } + }, + "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-ecs-integ/EcsCluster/graviton-cluster" + } + ] + } + }, + "EcsClustergravitonclusterLifecycleHookDrainHookA1F91B1B": { + "Type": "AWS::AutoScaling::LifecycleHook", + "Properties": { + "AutoScalingGroupName": { + "Ref": "EcsClustergravitonclusterASG869F3168" + }, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", + "DefaultResult": "CONTINUE", + "HeartbeatTimeout": 300, + "NotificationTargetARN": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + }, + "RoleARN": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD", + "Arn" + ] + } + }, + "DependsOn": [ + "EcsClustergravitonclusterLifecycleHookDrainHookRoleDefaultPolicy516A6DA7", + "EcsClustergravitonclusterLifecycleHookDrainHookRoleA16C85AD" + ] + } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/arm64/recommended/image_id" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.ts b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.ts new file mode 100644 index 0000000000000..4ca63a18a2262 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.graviton.ts @@ -0,0 +1,16 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as ecs from '../../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ'); + +const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2 }); +const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + +cluster.addCapacity('graviton-cluster', { + minCapacity: 2, + instanceType: new ec2.InstanceType('c6g.large'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.ARM), +}); +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json index 252359bbea4ee..1fef2d83e2784 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-awsvpc-nw.expected.json @@ -484,7 +484,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -1075,6 +1077,12 @@ } } }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } + }, "Outputs": { "LoadBalancerDNS": { "Value": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json index cd5d383c8d5a8..1bcb9d34f8dbd 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.lb-bridge-nw.expected.json @@ -505,7 +505,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -1039,6 +1041,12 @@ } } }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } + }, "Outputs": { "LoadBalancerDNS": { "Value": { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json index 5ee8ceb825f7b..353debc6de544 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-awsvpc-nw.expected.json @@ -484,7 +484,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -988,5 +990,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json index 6295444de267b..4722ee003bef2 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.sd-bridge-nw.expected.json @@ -484,7 +484,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -953,5 +955,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json index a290b4b72a020..20ba3cf89516e 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.spot-drain.expected.json @@ -484,7 +484,9 @@ "EcsClusterasgSpotLaunchConfig75BCA823": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "c5.xlarge", "IamInstanceProfile": { "Ref": "EcsClusterasgSpotInstanceProfile0D6DD08D" @@ -964,7 +966,9 @@ "EcsClusterasgOdLaunchConfigD3B9E271": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.large", "IamInstanceProfile": { "Ref": "EcsClusterasgOdInstanceProfileE5B88756" @@ -1383,5 +1387,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json index 4380259788434..c6efbdee23f66 100644 --- a/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.firelens-cloudwatch.expected.json @@ -433,7 +433,9 @@ "FirelensConfiguration": { "Type": "fluentbit" }, - "Image": "{{resolve:ssm:/aws/service/aws-for-fluent-bit/latest}}", + "Image": { + "Ref": "SsmParameterValueawsserviceawsforfluentbitlatestC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "LogConfiguration": { "LogDriver": "awslogs", "Options": { @@ -595,5 +597,11 @@ } } } + }, + "Parameters": { + "SsmParameterValueawsserviceawsforfluentbitlatestC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/aws-for-fluent-bit/latest" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index 254821c2af474..2d31b8dcf986a 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json index eb937ac5b7f25..f98225e84b35e 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.defaults.expected.json @@ -775,13 +775,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "ClusterResourceHandlerServiceRole7FB16465", "Arn" ] }, - "Handler": "index.handler", + "Runtime": "python3.7", "Layers": [ { "Fn::GetAtt": [ @@ -791,7 +792,6 @@ } ], "MemorySize": 512, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -891,12 +891,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "ClusterResourceHandlerServiceRole7FB16465", "Arn" ] }, + "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -904,7 +906,6 @@ } } }, - "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -914,7 +915,6 @@ } ], "MemorySize": 256, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -1117,7 +1117,9 @@ "ClusterDefaultCapacityLaunchConfig72790CF7": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "m5.large", "IamInstanceProfile": { "Ref": "ClusterDefaultCapacityInstanceProfile70387741" @@ -1304,6 +1306,10 @@ "AssetParameters640847533c8a00b3133aeb128edcac41fb7b60349c9e18764fcf7ea4af14d444ArtifactHash606C8127": { "Type": "String", "Description": "Artifact hash for asset \"640847533c8a00b3133aeb128edcac41fb7b60349c9e18764fcf7ea4af14d444\"" + }, + "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.kubectl-disabled.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.kubectl-disabled.expected.json index 8dd0f5e3967e1..66e63cb1a7497 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.kubectl-disabled.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.kubectl-disabled.expected.json @@ -902,7 +902,9 @@ "EKSClusterNodesLaunchConfig921F1106": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.medium", "IamInstanceProfile": { "Ref": "EKSClusterNodesInstanceProfile0F2DB3B9" @@ -1032,5 +1034,11 @@ ] } } + }, + "Parameters": { + "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json index 11cf4d6615d56..254e46a33dfd5 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-cluster.lit.expected.json @@ -775,13 +775,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "EKSClusterResourceHandlerServiceRoleFD631254", "Arn" ] }, - "Handler": "index.handler", + "Runtime": "python3.7", "Layers": [ { "Fn::GetAtt": [ @@ -791,7 +792,6 @@ } ], "MemorySize": 512, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -891,12 +891,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "EKSClusterResourceHandlerServiceRoleFD631254", "Arn" ] }, + "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -904,7 +906,6 @@ } } }, - "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -914,7 +915,6 @@ } ], "MemorySize": 256, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -1117,7 +1117,9 @@ "EKSClusterNodesLaunchConfig921F1106": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.medium", "IamInstanceProfile": { "Ref": "EKSClusterNodesInstanceProfile0F2DB3B9" @@ -1304,6 +1306,10 @@ "AssetParameters640847533c8a00b3133aeb128edcac41fb7b60349c9e18764fcf7ea4af14d444ArtifactHash606C8127": { "Type": "String", "Description": "Artifact hash for asset \"640847533c8a00b3133aeb128edcac41fb7b60349c9e18764fcf7ea4af14d444\"" + }, + "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json index 1fce7bbf583bd..ba37ddbe77d70 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-helm.lit.expected.json @@ -639,13 +639,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, - "Handler": "index.handler", + "Runtime": "python3.7", "Layers": [ { "Fn::GetAtt": [ @@ -655,7 +656,6 @@ } ], "MemorySize": 512, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -749,12 +749,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, + "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -762,7 +764,6 @@ } } }, - "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -772,7 +773,6 @@ } ], "MemorySize": 256, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -1010,7 +1010,9 @@ "cluster22NodesLaunchConfig184BF3BA": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.medium", "IamInstanceProfile": { "Ref": "cluster22NodesInstanceProfile3D4963ED" @@ -1157,12 +1159,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, + "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -1170,7 +1174,6 @@ } } }, - "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -1180,7 +1183,6 @@ } ], "MemorySize": 256, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -1324,6 +1326,10 @@ "AssetParameters8e2989bd32b411eba804b201a0f3984c984893c7fe6daa0b572fdd59c63e3653ArtifactHash77099D9F": { "Type": "String", "Description": "Artifact hash for asset \"8e2989bd32b411eba804b201a0f3984c984893c7fe6daa0b572fdd59c63e3653\"" + }, + "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" } } } diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json index 65e207c725e40..fd726b6e62f29 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-kubectl.lit.expected.json @@ -639,13 +639,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, - "Handler": "index.handler", + "Runtime": "python3.7", "Layers": [ { "Fn::GetAtt": [ @@ -655,7 +656,6 @@ } ], "MemorySize": 512, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -749,12 +749,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "cluster22ResourceHandlerServiceRoleC2E4F327", "Arn" ] }, + "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -762,7 +764,6 @@ } } }, - "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -772,7 +773,6 @@ } ], "MemorySize": 256, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -1010,7 +1010,9 @@ "cluster22NodesLaunchConfig184BF3BA": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.medium", "IamInstanceProfile": { "Ref": "cluster22NodesInstanceProfile3D4963ED" @@ -1208,6 +1210,10 @@ "AssetParameters640847533c8a00b3133aeb128edcac41fb7b60349c9e18764fcf7ea4af14d444ArtifactHash606C8127": { "Type": "String", "Description": "Artifact hash for asset \"640847533c8a00b3133aeb128edcac41fb7b60349c9e18764fcf7ea4af14d444\"" + }, + "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" } } } diff --git a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json index b68633208c82a..56f7f71864838 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json +++ b/packages/@aws-cdk/aws-eks-legacy/test/integ.eks-spot.expected.json @@ -613,13 +613,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "myClusterResourceHandlerServiceRole95F554E2", "Arn" ] }, - "Handler": "index.handler", + "Runtime": "python3.7", "Layers": [ { "Fn::GetAtt": [ @@ -629,7 +630,6 @@ } ], "MemorySize": 512, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -723,12 +723,14 @@ ] } }, + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "myClusterResourceHandlerServiceRole95F554E2", "Arn" ] }, + "Runtime": "python3.7", "Environment": { "Variables": { "CLUSTER_NAME": { @@ -736,7 +738,6 @@ } } }, - "Handler": "index.handler", "Layers": [ { "Fn::GetAtt": [ @@ -746,7 +747,6 @@ } ], "MemorySize": 256, - "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -949,7 +949,9 @@ "myClusterDefaultCapacityLaunchConfigCF6D4B81": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "m5.large", "IamInstanceProfile": { "Ref": "myClusterDefaultCapacityInstanceProfileE7E48198" @@ -1268,7 +1270,9 @@ "myClusterspotLaunchConfig6681F311": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.large", "IamInstanceProfile": { "Ref": "myClusterspotInstanceProfile93D80EE5" @@ -1438,6 +1442,10 @@ "AssetParameters640847533c8a00b3133aeb128edcac41fb7b60349c9e18764fcf7ea4af14d444ArtifactHash606C8127": { "Type": "String", "Description": "Artifact hash for asset \"640847533c8a00b3133aeb128edcac41fb7b60349c9e18764fcf7ea4af14d444\"" + }, + "SsmParameterValueawsserviceeksoptimizedami114amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.14/amazon-linux-2/recommended/image_id" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts b/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts index 6f7a3b33b4dc4..cfcc21a8ce50e 100644 --- a/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks-legacy/test/test.cluster.ts @@ -564,7 +564,7 @@ export = { 'EKS-Optimized AMI with GPU support'(test: Test) { // GIVEN - const { stack } = testFixtureNoVpc(); + const { app, stack } = testFixtureNoVpc(); // WHEN new eks.Cluster(stack, 'cluster', { @@ -573,9 +573,11 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/eks/optimized-ami/1.14/amazon-linux2-gpu/recommended/image_id}}', - })); + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template.Parameters; + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && (v as any).Default.includes('amazon-linux2-gpu'), + ), 'EKS AMI with GPU should be in ssm parameters'); test.done(); }, }; diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 6384568e8e857..c91c1630858c4 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -70,7 +70,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.75", + "@types/aws-lambda": "^8.10.76", "@types/sinon": "^9.0.11", "@types/nodeunit": "^0.0.31", "@types/yaml": "1.9.6", diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json index 0ff855468f38c..de8e6fe0bf8ae 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json @@ -1652,7 +1652,9 @@ "ClusterNodesLaunchConfig7C420A27": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.medium", "IamInstanceProfile": { "Ref": "ClusterNodesInstanceProfileF2DD0E21" @@ -1975,7 +1977,9 @@ "ClusterNodesArmLaunchConfigAAF61344": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2-arm64/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "m6g.medium", "IamInstanceProfile": { "Ref": "ClusterNodesArmInstanceProfile158C5C9F" @@ -2298,7 +2302,9 @@ "ClusterBottlerocketNodesLaunchConfig76D7BEBE": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/bottlerocket/aws-k8s-1.19/x86_64/latest/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsservicebottlerocketawsk8s119x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.small", "IamInstanceProfile": { "Ref": "ClusterBottlerocketNodesInstanceProfileB6E2F25A" @@ -2621,7 +2627,9 @@ "ClusterspotLaunchConfigCC19F2E6": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.large", "IamInstanceProfile": { "Ref": "ClusterspotInstanceProfileAB88D077" @@ -2977,7 +2985,9 @@ "ClusterInferenceInstancesLaunchConfig03BF48FE": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2-gpu/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "inf1.2xlarge", "IamInstanceProfile": { "Ref": "ClusterInferenceInstancesInstanceProfile5A1209B4" @@ -4018,7 +4028,9 @@ "Type": "AWS::EC2::LaunchTemplate", "Properties": { "LaunchTemplateData": { - "ImageId": "{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.small", "UserData": { "Fn::Base64": { @@ -4765,6 +4777,22 @@ "AssetParameterse334ff007b5126b62d66d4baac94004f4281dc2b0b0c4685ec93e330cb59e921ArtifactHash31BE978F": { "Type": "String", "Description": "Artifact hash for asset \"e334ff007b5126b62d66d4baac94004f4281dc2b0b0c4685ec93e330cb59e921\"" + }, + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id" + }, + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2arm64recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2-arm64/recommended/image_id" + }, + "SsmParameterValueawsservicebottlerocketawsk8s119x8664latestimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/bottlerocket/aws-k8s-1.19/x86_64/latest/image_id" + }, + "SsmParameterValueawsserviceeksoptimizedami119amazonlinux2gpurecommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/eks/optimized-ami/1.19/amazon-linux-2-gpu/recommended/image_id" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 5db1ced5f0e71..3a1866d6f460b 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -1437,26 +1437,44 @@ export = { 'EksOptimizedImage() with no nodeType always uses STANDARD with LATEST_KUBERNETES_VERSION'(test: Test) { // GIVEN - const { stack } = testFixtureNoVpc(); + const { app, stack } = testFixtureNoVpc(); const LATEST_KUBERNETES_VERSION = '1.14'; // WHEN - const machineImageConfig = new eks.EksOptimizedImage().getImage(stack); + new eks.EksOptimizedImage().getImage(stack); // THEN - test.equal(stack.resolve(machineImageConfig.imageId), `{{resolve:ssm:/aws/service/eks/optimized-ami/${LATEST_KUBERNETES_VERSION}/amazon-linux-2/recommended/image_id}}`); + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template.Parameters; + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && + (v as any).Default.includes('/amazon-linux-2/'), + ), 'EKS STANDARD AMI should be in ssm parameters'); + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && + (v as any).Default.includes(LATEST_KUBERNETES_VERSION), + ), 'LATEST_KUBERNETES_VERSION should be in ssm parameters'); test.done(); }, 'EksOptimizedImage() with specific kubernetesVersion return correct AMI'(test: Test) { // GIVEN - const { stack } = testFixtureNoVpc(); + const { app, stack } = testFixtureNoVpc(); // WHEN - const machineImageConfig = new eks.EksOptimizedImage({ kubernetesVersion: '1.19' }).getImage(stack); + new eks.EksOptimizedImage({ kubernetesVersion: '1.19' }).getImage(stack); // THEN - test.equal(stack.resolve(machineImageConfig.imageId), '{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id}}'); + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template.Parameters; + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && + (v as any).Default.includes('/amazon-linux-2/'), + ), 'EKS STANDARD AMI should be in ssm parameters'); + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && + (v as any).Default.includes('/1.19/'), + ), 'kubernetesVersion should be in ssm parameters'); test.done(); }, @@ -1523,7 +1541,7 @@ export = { 'addAutoScalingGroupCapacity with T4g instance type comes with nodegroup with correct AmiType'(test: Test) { // GIVEN - const { stack } = testFixtureNoVpc(); + const { app, stack } = testFixtureNoVpc(); // WHEN new eks.Cluster(stack, 'cluster', { @@ -1535,15 +1553,18 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2-arm64/recommended/image_id}}', - })); + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template.Parameters; + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && + (v as any).Default.includes('amazon-linux-2-arm64/'), + ), 'Amazon Linux 2 AMI for ARM64 should be in ssm parameters'); test.done(); }, 'EKS-Optimized AMI with GPU support when addAutoScalingGroupCapacity'(test: Test) { // GIVEN - const { stack } = testFixtureNoVpc(); + const { app, stack } = testFixtureNoVpc(); // WHEN new eks.Cluster(stack, 'cluster', { @@ -1555,15 +1576,17 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2-gpu/recommended/image_id}}', - })); + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template.Parameters; + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && (v as any).Default.includes('amazon-linux-2-gpu'), + ), 'EKS AMI with GPU should be in ssm parameters'); test.done(); }, 'EKS-Optimized AMI with ARM64 when addAutoScalingGroupCapacity'(test: Test) { // GIVEN - const { stack } = testFixtureNoVpc(); + const { app, stack } = testFixtureNoVpc(); // WHEN new eks.Cluster(stack, 'cluster', { @@ -1575,21 +1598,32 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::AutoScaling::LaunchConfiguration', { - ImageId: '{{resolve:ssm:/aws/service/eks/optimized-ami/1.19/amazon-linux-2-arm64/recommended/image_id}}', - })); + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template.Parameters; + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') && (v as any).Default.includes('/amazon-linux-2-arm64/'), + ), 'EKS AMI with GPU should be in ssm parameters'); test.done(); }, 'BottleRocketImage() with specific kubernetesVersion return correct AMI'(test: Test) { // GIVEN - const { stack } = testFixtureNoVpc(); + const { app, stack } = testFixtureNoVpc(); // WHEN - const machineImageConfig = new BottleRocketImage({ kubernetesVersion: '1.19' }).getImage(stack); + new BottleRocketImage({ kubernetesVersion: '1.19' }).getImage(stack); // THEN - test.equal(stack.resolve(machineImageConfig).imageId, '{{resolve:ssm:/aws/service/bottlerocket/aws-k8s-1.19/x86_64/latest/image_id}}'); + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template.Parameters; + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsservicebottlerocketaws') && + (v as any).Default.includes('/bottlerocket/'), + ), 'BottleRocket AMI should be in ssm parameters'); + test.ok(Object.entries(parameters).some( + ([k, v]) => k.startsWith('SsmParameterValueawsservicebottlerocketaws') && + (v as any).Default.includes('/aws-k8s-1.19/'), + ), 'kubernetesVersion should be in ssm parameters'); test.done(); }, diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index f25db93b1ee2e..a21ff8758d2a3 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index e782c89e20434..186248ef4f9a2 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index 4140a437178f8..355f293831e16 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index 0f291baea882a..0ff664c1fa5ae 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json @@ -63,7 +63,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index bf5f432995bd9..e9320a50a95c1 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -63,7 +63,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts index 8d0312977e092..f738fbcf65bc4 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts @@ -239,6 +239,7 @@ export class NetworkListener extends BaseListener implements INetworkListener { port: props.port, protocol: props.protocol ?? this.protocol, proxyProtocolV2: props.proxyProtocolV2, + preserveClientIp: props.preserveClientIp, targetGroupName: props.targetGroupName, targets: props.targets, vpc: this.loadBalancer.vpc, @@ -333,6 +334,14 @@ export interface AddNetworkTargetsProps { */ readonly proxyProtocolV2?: boolean; + /** + * Indicates whether client IP preservation is enabled. + * + * @default false if the target group type is IP address and the + * target group protocol is TCP or TLS. Otherwise, true. + */ + readonly preserveClientIp?: boolean; + /** * Health check configuration * diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts index 3c2e3cb574609..f4ac146d8209d 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts @@ -33,6 +33,14 @@ export interface NetworkTargetGroupProps extends BaseTargetGroupProps { */ readonly proxyProtocolV2?: boolean; + /** + * Indicates whether client IP preservation is enabled. + * + * @default false if the target group type is IP address and the + * target group protocol is TCP or TLS. Otherwise, true. + */ + readonly preserveClientIp?: boolean; + /** * The targets to add to this target group. * @@ -82,6 +90,10 @@ export class NetworkTargetGroup extends TargetGroupBase implements INetworkTarge this.setAttribute('proxy_protocol_v2.enabled', props.proxyProtocolV2 ? 'true' : 'false'); } + if (props.preserveClientIp !== undefined) { + this.setAttribute('preserve_client_ip.enabled', props.preserveClientIp ? 'true' : 'false'); + } + this.addTarget(...(props.targets || [])); } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index 3f2783180568b..fcf13262f8068 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts index bdddc74b2fd53..90aa39b37141b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts @@ -28,6 +28,29 @@ describe('tests', () => { }); }); + test('Enable preserve_client_ip attribute for target group', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'Group', { + vpc, + port: 80, + preserveClientIp: true, + }); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + TargetGroupAttributes: [ + { + Key: 'preserve_client_ip.enabled', + Value: 'true', + }, + ], + }); + }); + test('Disable proxy protocol v2 for attribute target group', () => { // GIVEN const stack = new cdk.Stack(); @@ -51,6 +74,29 @@ describe('tests', () => { }); }); + test('Disable preserve_client_ip attribute for target group', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'Group', { + vpc, + port: 80, + preserveClientIp: false, + }); + + // THEN + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + TargetGroupAttributes: [ + { + Key: 'preserve_client_ip.enabled', + Value: 'false', + }, + ], + }); + }); + test('Configure protocols for target group', () => { const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'Vpc'); diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 9ebbb4bfce4e8..e7bfd0e784754 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index 520b43c25c0ca..f666c85ab19ef 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-emrcontainers/package.json b/packages/@aws-cdk/aws-emrcontainers/package.json index 9f1df1b77c049..217671443029d 100644 --- a/packages/@aws-cdk/aws-emrcontainers/package.json +++ b/packages/@aws-cdk/aws-emrcontainers/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 2dd422fee9626..e36df0baf5c71 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", @@ -85,7 +85,6 @@ }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -107,7 +106,6 @@ "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-apigateway": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json index 715521127e6f2..dbdb415e57e63 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/integ.event-ec2-task.lit.expected.json @@ -325,7 +325,9 @@ "EcsClusterDefaultAutoScalingGroupLaunchConfigB7E376C1": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "EcsClusterDefaultAutoScalingGroupInstanceProfile2CE606B3" @@ -926,5 +928,11 @@ ] } } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index 62062014bafbc..6fedbeab06ca7 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-fis/package.json b/packages/@aws-cdk/aws-fis/package.json index 709bd2d6018f2..54d5b6266b4bb 100644 --- a/packages/@aws-cdk/aws-fis/package.json +++ b/packages/@aws-cdk/aws-fis/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index 32fbe8a0f8992..15b4d8bf278f4 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index 388fd2f5745e0..39f3d0f924780 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json index 263e4f374715f..c5826b996a6bf 100644 --- a/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json +++ b/packages/@aws-cdk/aws-fsx/test/integ.lustre-file-system.expected.json @@ -669,7 +669,9 @@ "IamInstanceProfile": { "Ref": "instInstanceProfile59FAEED2" }, - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.large", "SecurityGroupIds": [ { @@ -696,5 +698,11 @@ "instInstanceRoleFE783FB1" ] } + }, + "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index c6af3b1137383..8d267810b451f 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json index f6ebff541034d..41b96969792fc 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json @@ -68,7 +68,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/assert-internal": "0.0.0", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json index 9b119ffa11bc5..72b6e81da9827 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/test/integ.globalaccelerator.expected.json @@ -656,7 +656,9 @@ "IamInstanceProfile": { "Ref": "Instance0InstanceProfile3A61DE71" }, - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.small", "SecurityGroupIds": [ { @@ -755,7 +757,9 @@ "IamInstanceProfile": { "Ref": "Instance1InstanceProfileC04770B7" }, - "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t3.small", "SecurityGroupIds": [ { @@ -968,6 +972,10 @@ } }, "Parameters": { + "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" + }, "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { "Type": "String", "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" @@ -981,4 +989,4 @@ "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" } } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index 2d127f318c347..31fbba06e5bc0 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "cdk-integ-tools": "0.0.0", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index 3ad772daabf4a..22ba5fa62de53 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index 0c58e1f0ccc63..b7bb106d71430 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-greengrassv2/package.json b/packages/@aws-cdk/aws-greengrassv2/package.json index 5622bc8455870..a891481eb42d0 100644 --- a/packages/@aws-cdk/aws-greengrassv2/package.json +++ b/packages/@aws-cdk/aws-greengrassv2/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-groundstation/package.json b/packages/@aws-cdk/aws-groundstation/package.json index 31e5952eb6828..db78ba45da026 100644 --- a/packages/@aws-cdk/aws-groundstation/package.json +++ b/packages/@aws-cdk/aws-groundstation/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/assert-internal": "0.0.0", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index f45e506956bfe..16fbd30cfd959 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index 805cdefe1fa60..e681fbdce8bff 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -78,8 +78,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.62", - "@types/jest": "^26.0.22", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", "@types/sinon": "^9.0.11", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-imagebuilder/package.json b/packages/@aws-cdk/aws-imagebuilder/package.json index 3aedf769d6bf4..5a46b27b57ae7 100644 --- a/packages/@aws-cdk/aws-imagebuilder/package.json +++ b/packages/@aws-cdk/aws-imagebuilder/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index c58891dd1744f..4dd122dd74ed4 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index 91b50354450d2..eafe42218f351 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index be420d903fee2..6415b79eb5455 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index 6ef22f794d8e9..cef522564fd76 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index a6c4f15cc28cc..6bb31f8bac0ba 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotfleethub/package.json b/packages/@aws-cdk/aws-iotfleethub/package.json index 717d1552c9882..8141a2172be4a 100644 --- a/packages/@aws-cdk/aws-iotfleethub/package.json +++ b/packages/@aws-cdk/aws-iotfleethub/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/assert-internal": "0.0.0", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotsitewise/package.json b/packages/@aws-cdk/aws-iotsitewise/package.json index a5abe692bd6f4..9108aadc41ceb 100644 --- a/packages/@aws-cdk/aws-iotsitewise/package.json +++ b/packages/@aws-cdk/aws-iotsitewise/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index 563601a46c4e7..f20d59c696eb6 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotwireless/package.json b/packages/@aws-cdk/aws-iotwireless/package.json index dd727b6e531ec..d729950fecafd 100644 --- a/packages/@aws-cdk/aws-iotwireless/package.json +++ b/packages/@aws-cdk/aws-iotwireless/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-ivs/package.json b/packages/@aws-cdk/aws-ivs/package.json index cb781a3ebf604..6c101281a4146 100644 --- a/packages/@aws-cdk/aws-ivs/package.json +++ b/packages/@aws-cdk/aws-ivs/package.json @@ -83,7 +83,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json index 2dda529ea38fd..7732f5310c7cc 100644 --- a/packages/@aws-cdk/aws-kendra/package.json +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesis/README.md b/packages/@aws-cdk/aws-kinesis/README.md index ebf5bdb74e3ae..1e7aaf89a5a88 100644 --- a/packages/@aws-cdk/aws-kinesis/README.md +++ b/packages/@aws-cdk/aws-kinesis/README.md @@ -24,6 +24,7 @@ intake and aggregation. - [Read Permissions](#read-permissions) - [Write Permissions](#write-permissions) - [Custom Permissions](#custom-permissions) + - [Metrics](#metrics) ## Streams @@ -192,3 +193,21 @@ const stream = new Stream(stack, 'MyStream'); // give my user permissions to list shards stream.grant(user, 'kinesis:ListShards'); ``` + +### Metrics + +You can use common metrics from your stream to create alarms and/or dashboards. The `stream.metric('MetricName')` method creates a metric with the stream namespace and dimension. You can also use pre-define methods like `stream.metricGetRecordsSuccess()`. To find out more about Kinesis metrics check [Monitoring the Amazon Kinesis Data Streams Service with Amazon CloudWatch](https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html). + +```ts +const stream = new Stream(stack, 'MyStream'); + +// Using base metric method passing the metric name +stream.metric('GetRecords.Success'); + +// using pre-defined metric method +stream.metricGetRecordsSuccess(); + +// using pre-defined and overriding the statistic +stream.metricGetRecordsSuccess({ statistic: 'Maximum' }); +``` + diff --git a/packages/@aws-cdk/aws-kinesis/lib/kinesis-fixed-canned-metrics.ts b/packages/@aws-cdk/aws-kinesis/lib/kinesis-fixed-canned-metrics.ts new file mode 100644 index 0000000000000..a10434d947bbf --- /dev/null +++ b/packages/@aws-cdk/aws-kinesis/lib/kinesis-fixed-canned-metrics.ts @@ -0,0 +1,129 @@ +import { KinesisMetrics as CannedMetrics } from './kinesis-canned-metrics.generated'; + +/** + * This class is to consolidate all the metrics from Stream in just one place. + * + * Current generated canned metrics don't match the proper metrics from the service. If it is fixed + * at the source this class can be removed and just use the generated one directly. + * + * Stream Metrics reference: https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html + */ +export class KinesisMetrics { + public static getRecordsBytesAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Bytes', + dimensions, + statistic: 'Average', + }; + } + public static getRecordsSuccessAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Success', + dimensions, + statistic: 'Average', + }; + } + public static getRecordsRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Records', + dimensions, + statistic: 'Average', + }; + } + public static getRecordsLatencyAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Latency', + dimensions, + statistic: 'Average', + }; + } + public static putRecordBytesAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecord.Bytes', + dimensions, + statistic: 'Average', + }; + } + public static putRecordLatencyAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecord.Latency', + dimensions, + statistic: 'Average', + }; + } + public static getRecordsIteratorAgeMillisecondsMaximum(dimensions: { StreamName: string }) { + return CannedMetrics.getRecordsIteratorAgeMillisecondsMaximum(dimensions); + } + public static putRecordSuccessAverage(dimensions: { StreamName: string }) { + return CannedMetrics.putRecordSuccessAverage(dimensions); + } + public static putRecordsBytesAverage(dimensions: { StreamName: string }) { + return CannedMetrics.putRecordsBytesAverage(dimensions); + } + public static putRecordsLatencyAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Latency', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsSuccessAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Success', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsTotalRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.TotalRecords', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsSuccessfulRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.SuccessfulRecords', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsFailedRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.FailedRecords', + dimensions, + statistic: 'Average', + }; + } + public static putRecordsThrottledRecordsAverage(dimensions: { StreamName: string }) { + return { + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.ThrottledRecords', + dimensions, + statistic: 'Average', + }; + } + public static incomingBytesAverage(dimensions: { StreamName: string }) { + return CannedMetrics.incomingBytesAverage(dimensions); + } + public static incomingRecordsAverage(dimensions: { StreamName: string }) { + return CannedMetrics.incomingRecordsAverage(dimensions); + } + public static readProvisionedThroughputExceededAverage(dimensions: { StreamName: string }) { + return CannedMetrics.readProvisionedThroughputExceededAverage(dimensions); + } + public static writeProvisionedThroughputExceededAverage(dimensions: { StreamName: string }) { + return CannedMetrics.writeProvisionedThroughputExceededAverage(dimensions); + } +} diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index a0e7acef57594..0a73c6b9062f8 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -1,7 +1,9 @@ +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { Aws, CfnCondition, Duration, Fn, IResolvable, IResource, Resource, Stack, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { KinesisMetrics } from './kinesis-fixed-canned-metrics'; import { CfnStream } from './kinesis.generated'; const READ_OPERATIONS = [ @@ -72,6 +74,217 @@ export interface IStream extends IResource { * Grant the indicated permissions on this stream to the provided IAM principal. */ grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant; + + /** + * Return stream metric based from its metric name + * + * @param metricName name of the stream metric + * @param props properties of the metric + */ + metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of bytes retrieved from the Kinesis stream, measured over the specified time period. Minimum, Maximum, + * and Average statistics represent the bytes in a single GetRecords operation for the stream in the specified time + * period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecordsBytes(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The age of the last record in all GetRecords calls made against a Kinesis stream, measured over the specified time + * period. Age is the difference between the current time and when the last record of the GetRecords call was written + * to the stream. The Minimum and Maximum statistics can be used to track the progress of Kinesis consumer + * applications. A value of zero indicates that the records being read are completely caught up with the stream. + * + * The metric defaults to maximum over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecordsIteratorAgeMilliseconds(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time taken per GetRecords operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecordsLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records retrieved from the shard, measured over the specified time period. Minimum, Maximum, and + * Average statistics represent the records in a single GetRecords operation for the stream in the specified time + * period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of successful GetRecords operations per stream, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricGetRecordsSuccess(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of bytes successfully put to the Kinesis stream over the specified time period. This metric includes + * bytes from PutRecord and PutRecords operations. Minimum, Maximum, and Average statistics represent the bytes in a + * single put operation for the stream in the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricIncomingBytes(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records successfully put to the Kinesis stream over the specified time period. This metric includes + * record counts from PutRecord and PutRecords operations. Minimum, Maximum, and Average statistics represent the + * records in a single put operation for the stream in the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricIncomingRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of bytes put to the Kinesis stream using the PutRecord operation over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordBytes(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time taken per PutRecord operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of successful PutRecord operations per Kinesis stream, measured over the specified time period. Average + * reflects the percentage of successful writes to a stream. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordSuccess(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of bytes put to the Kinesis stream using the PutRecords operation over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsBytes(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The time taken per PutRecords operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsLatency(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of PutRecords operations where at least one record succeeded, per Kinesis stream, measured over the + * specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsSuccess(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The total number of records sent in a PutRecords operation per Kinesis data stream, measured over the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsTotalRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of successful records in a PutRecords operation per Kinesis data stream, measured over the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsSuccessfulRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records rejected due to internal failures in a PutRecords operation per Kinesis data stream, + * measured over the specified time period. Occasional internal failures are to be expected and should be retried. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsFailedRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records rejected due to throttling in a PutRecords operation per Kinesis data stream, measured over + * the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordsThrottledRecords(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of GetRecords calls throttled for the stream over the specified time period. The most commonly used + * statistic for this metric is Average. + * + * When the Minimum statistic has a value of 1, all records were throttled for the stream during the specified time + * period. + * + * When the Maximum statistic has a value of 0 (zero), no records were throttled for the stream during the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties + * + * @param props properties of the metric + * + */ + metricReadProvisionedThroughputExceeded(props?: cloudwatch.MetricOptions): cloudwatch.Metric; + + /** + * The number of records rejected due to throttling for the stream over the specified time period. This metric + * includes throttling from PutRecord and PutRecords operations. + * + * When the Minimum statistic has a non-zero value, records were being throttled for the stream during the specified + * time period. + * + * When the Maximum statistic has a value of 0 (zero), no records were being throttled for the stream during the + * specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricWriteProvisionedThroughputExceeded(props?: cloudwatch.MetricOptions): cloudwatch.Metric; } /** @@ -168,6 +381,276 @@ abstract class StreamBase extends Resource implements IStream { scope: this, }); } + + /** + * Return stream metric based from its metric name + * + * @param metricName name of the stream metric + * @param props properties of the metric + */ + public metric(metricName: string, props?: cloudwatch.MetricOptions) { + return new cloudwatch.Metric({ + namespace: 'AWS/Kinesis', + metricName, + dimensions: { + StreamName: this.streamName, + }, + ...props, + }).attachTo(this); + } + + /** + * The number of bytes retrieved from the Kinesis stream, measured over the specified time period. Minimum, Maximum, + * and Average statistics represent the bytes in a single GetRecords operation for the stream in the specified time + * period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecordsBytes(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsBytesAverage, props); + } + + /** + * The age of the last record in all GetRecords calls made against a Kinesis stream, measured over the specified time + * period. Age is the difference between the current time and when the last record of the GetRecords call was written + * to the stream. The Minimum and Maximum statistics can be used to track the progress of Kinesis consumer + * applications. A value of zero indicates that the records being read are completely caught up with the stream. + * + * The metric defaults to maximum over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecordsIteratorAgeMilliseconds(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsIteratorAgeMillisecondsMaximum, props); + } + + /** + * The number of successful GetRecords operations per stream, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecordsSuccess(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsSuccessAverage, props); + } + + /** + * The number of records retrieved from the shard, measured over the specified time period. Minimum, Maximum, and + * Average statistics represent the records in a single GetRecords operation for the stream in the specified time + * period. + * + * average + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsRecordsAverage, props); + } + + /** + * The number of successful GetRecords operations per stream, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricGetRecordsLatency(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.getRecordsLatencyAverage, props); + } + + /** + * The number of bytes put to the Kinesis stream using the PutRecord operation over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordBytes(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordBytesAverage, props); + } + + /** + * The time taken per PutRecord operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + metricPutRecordLatency(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordLatencyAverage, props); + } + + /** + * The number of successful PutRecord operations per Kinesis stream, measured over the specified time period. Average + * reflects the percentage of successful writes to a stream. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordSuccess(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordSuccessAverage, props); + } + + /** + * The number of bytes put to the Kinesis stream using the PutRecords operation over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsBytes(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsBytesAverage, props); + } + + /** + * The time taken per PutRecords operation, measured over the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsLatency(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsLatencyAverage, props); + } + + /** + * The number of PutRecords operations where at least one record succeeded, per Kinesis stream, measured over the + * specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsSuccess(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsSuccessAverage, props); + } + + /** + * The total number of records sent in a PutRecords operation per Kinesis data stream, measured over the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsTotalRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsTotalRecordsAverage, props); + } + + /** + * The number of successful records in a PutRecords operation per Kinesis data stream, measured over the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsSuccessfulRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsSuccessfulRecordsAverage, props); + } + + /** + * The number of records rejected due to internal failures in a PutRecords operation per Kinesis data stream, + * measured over the specified time period. Occasional internal failures are to be expected and should be retried. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsFailedRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsFailedRecordsAverage, props); + } + + /** + * The number of records rejected due to throttling in a PutRecords operation per Kinesis data stream, measured over + * the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricPutRecordsThrottledRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.putRecordsThrottledRecordsAverage, props); + } + + /** + * The number of bytes successfully put to the Kinesis stream over the specified time period. This metric includes + * bytes from PutRecord and PutRecords operations. Minimum, Maximum, and Average statistics represent the bytes in a + * single put operation for the stream in the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricIncomingBytes(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.incomingBytesAverage, props); + } + + /** + * The number of records successfully put to the Kinesis stream over the specified time period. This metric includes + * record counts from PutRecord and PutRecords operations. Minimum, Maximum, and Average statistics represent the + * records in a single put operation for the stream in the specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricIncomingRecords(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.incomingRecordsAverage, props); + } + + /** + * The number of GetRecords calls throttled for the stream over the specified time period. The most commonly used + * statistic for this metric is Average. + * + * When the Minimum statistic has a value of 1, all records were throttled for the stream during the specified time + * period. + * + * When the Maximum statistic has a value of 0 (zero), no records were throttled for the stream during the specified + * time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties + * + * @param props properties of the metric + * + */ + public metricReadProvisionedThroughputExceeded(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.readProvisionedThroughputExceededAverage, props); + } + + /** + * The number of records rejected due to throttling for the stream over the specified time period. This metric + * includes throttling from PutRecord and PutRecords operations. + * + * When the Minimum statistic has a non-zero value, records were being throttled for the stream during the specified + * time period. + * + * When the Maximum statistic has a value of 0 (zero), no records were being throttled for the stream during the + * specified time period. + * + * The metric defaults to average over 5 minutes, it can be changed by passing `statistic` and `period` properties. + * + * @param props properties of the metric + */ + public metricWriteProvisionedThroughputExceeded(props?: cloudwatch.MetricOptions) { + return this.metricFromCannedFunction(KinesisMetrics.writeProvisionedThroughputExceededAverage, props); + } + + // create metrics based on generated KinesisMetrics static methods + private metricFromCannedFunction( + createCannedProps: (dimensions: { StreamName: string }) => cloudwatch.MetricProps, + props?: cloudwatch.MetricOptions): cloudwatch.Metric { + return new cloudwatch.Metric({ + ...createCannedProps({ StreamName: this.streamName }), + ...props, + }).attachTo(this); + } + } /** diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index aac7861429dda..524b80508f273 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/cx-api": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -80,6 +80,7 @@ "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", @@ -88,6 +89,7 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.expected.json b/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.expected.json new file mode 100644 index 0000000000000..28a166e76fd1f --- /dev/null +++ b/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.expected.json @@ -0,0 +1,206 @@ +{ + "Resources": { + "myStream547FAD7F": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "ShardCount": 1, + "RetentionPeriodHours": 24, + "StreamEncryption": { + "Fn::If": [ + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", + { + "Ref": "AWS::NoValue" + }, + { + "EncryptionType": "KMS", + "KeyId": "alias/aws/kinesis" + } + ] + } + } + }, + "StreamDashboardAAF4FCF8": { + "Type": "AWS::CloudWatch::Dashboard", + "Properties": { + "DashboardBody": { + "Fn::Join": [ + "", + [ + "{\"widgets\":[{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":0,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records - sum (Bytes)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.Bytes\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":0,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records iterator age - maximum (Milliseconds)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.IteratorAgeMilliseconds\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Maximum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":5,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records latency - average (Milliseconds)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.Latency\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":5,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records - sum (Count)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.Records\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":10,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Get records success - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"GetRecords.Success\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":10,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Incoming data - sum (Bytes)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"IncomingBytes\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":15,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Incoming records - sum (Count)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"IncomingRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":15,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put record - sum (Bytes)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecord.Bytes\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":20,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put record latency - average (Milliseconds)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecord.Latency\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":20,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put record success - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecord.Success\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":25,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records - sum (Bytes)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecords.Bytes\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"stat\":\"Sum\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":25,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records latency - average (Milliseconds)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"PutRecords.Latency\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":30,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Read throughput exceeded - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"ReadProvisionedThroughputExceeded\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":30,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Write throughput exceeded - average (Count)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[\"AWS/Kinesis\",\"WriteProvisionedThroughputExceeded\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\"]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":35,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records successful records - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[{\"label\":\"( count / total ) * 100\",\"expression\":\"( count / total ) * 100\"}],[\"AWS/Kinesis\",\"PutRecords.SuccessfulRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"count\"}],[\"AWS/Kinesis\",\"PutRecords.TotalRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"total\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":12,\"y\":35,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records failed records - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[{\"label\":\"( count / total ) * 100\",\"expression\":\"( count / total ) * 100\"}],[\"AWS/Kinesis\",\"PutRecords.FailedRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"count\"}],[\"AWS/Kinesis\",\"PutRecords.TotalRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"total\"}]],\"yAxis\":{}}},{\"type\":\"metric\",\"width\":12,\"height\":5,\"x\":0,\"y\":40,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Put records throttled records - average (Percent)\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"metrics\":[[{\"label\":\"( count / total ) * 100\",\"expression\":\"( count / total ) * 100\"}],[\"AWS/Kinesis\",\"PutRecords.ThrottledRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"count\"}],[\"AWS/Kinesis\",\"PutRecords.TotalRecords\",\"StreamName\",\"", + { + "Ref": "myStream547FAD7F" + }, + "\",{\"visible\":false,\"id\":\"total\"}]],\"yAxis\":{}}}]}" + ] + ] + } + } + } + }, + "Conditions": { + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions": { + "Fn::Or": [ + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-north-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-northwest-1" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.ts b/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.ts new file mode 100644 index 0000000000000..cb1dcadf749be --- /dev/null +++ b/packages/@aws-cdk/aws-kinesis/test/integ.stream-dashboard.ts @@ -0,0 +1,57 @@ +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; +import { App, Stack } from '@aws-cdk/core'; +import { Stream } from '../lib'; + +const app = new App(); +const stack = new Stack(app, 'integ-kinesis-stream-dashboard'); + +const stream = new Stream(stack, 'myStream'); + +const dashboard = new cloudwatch.Dashboard(stack, 'StreamDashboard'); + +function graphWidget(title: string, metric: cloudwatch.Metric) { + return new cloudwatch.GraphWidget({ + title, + left: [metric], + width: 12, + height: 5, + }); +} + +function percentGraphWidget(title: string, countMetric: cloudwatch.Metric, totalMetric: cloudwatch.Metric) { + return new cloudwatch.GraphWidget({ + title, + left: [new cloudwatch.MathExpression({ + expression: '( count / total ) * 100', + usingMetrics: { + count: countMetric, + total: totalMetric, + }, + })], + width: 12, + height: 5, + }); +} + +dashboard.addWidgets( + graphWidget('Get records - sum (Bytes)', stream.metricGetRecordsBytes({ statistic: 'Sum' })), + graphWidget('Get records iterator age - maximum (Milliseconds)', stream.metricGetRecordsIteratorAgeMilliseconds()), + graphWidget('Get records latency - average (Milliseconds)', stream.metricGetRecordsLatency()), + graphWidget('Get records - sum (Count)', stream.metricGetRecords({ statistic: 'Sum' })), + graphWidget('Get records success - average (Percent)', stream.metricGetRecordsSuccess()), + graphWidget('Incoming data - sum (Bytes)', stream.metricIncomingBytes({ statistic: 'Sum' })), + graphWidget('Incoming records - sum (Count)', stream.metricIncomingRecords({ statistic: 'Sum' })), + graphWidget('Put record - sum (Bytes)', stream.metricPutRecordBytes({ statistic: 'Sum' })), + graphWidget('Put record latency - average (Milliseconds)', stream.metricPutRecordLatency()), + graphWidget('Put record success - average (Percent)', stream.metricPutRecordSuccess()), + graphWidget('Put records - sum (Bytes)', stream.metricPutRecordsBytes({ statistic: 'Sum' })), + graphWidget('Put records latency - average (Milliseconds)', stream.metricPutRecordsLatency()), + graphWidget('Read throughput exceeded - average (Percent)', stream.metricReadProvisionedThroughputExceeded()), + graphWidget('Write throughput exceeded - average (Count)', stream.metricWriteProvisionedThroughputExceeded()), + percentGraphWidget('Put records successful records - average (Percent)', + stream.metricPutRecordsSuccessfulRecords(), stream.metricPutRecordsTotalRecords()), + percentGraphWidget('Put records failed records - average (Percent)', + stream.metricPutRecordsFailedRecords(), stream.metricPutRecordsTotalRecords()), + percentGraphWidget('Put records throttled records - average (Percent)', + stream.metricPutRecordsThrottledRecords(), stream.metricPutRecordsTotalRecords()), +); diff --git a/packages/@aws-cdk/aws-kinesis/test/integ.stream.ts b/packages/@aws-cdk/aws-kinesis/test/integ.stream.ts index c44aa888f113c..e508ffe71b42b 100644 --- a/packages/@aws-cdk/aws-kinesis/test/integ.stream.ts +++ b/packages/@aws-cdk/aws-kinesis/test/integ.stream.ts @@ -11,4 +11,4 @@ const role = new iam.Role(stack, 'UserRole', { const stream = new Stream(stack, 'myStream'); -stream.grantReadWrite(role); \ No newline at end of file +stream.grantReadWrite(role); diff --git a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts index c9d307d27505e..388ac8b0caac5 100644 --- a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts +++ b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts @@ -1329,6 +1329,8 @@ describe('Kinesis data streams', () => { AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { 'Fn::Or': [ { + + 'Fn::Equals': [ { Ref: 'AWS::Region', @@ -1349,4 +1351,207 @@ describe('Kinesis data streams', () => { }, }); }); + + test('basic stream-level metrics (StreamName dimension only)', () => { + // GIVEN + const stack = new Stack(); + + const fiveMinutes = { + amount: 5, + unit: { + label: 'minutes', + isoLabel: 'M', + inMillis: 60000, + }, + }; + + // WHEN + const stream = new Stream(stack, 'MyStream'); + + // THEN + // should resolve the basic metrics (source https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html#kinesis-metrics-stream) + expect(stack.resolve(stream.metricGetRecordsBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Bytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricGetRecordsIteratorAgeMilliseconds())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.IteratorAgeMilliseconds', + period: fiveMinutes, + statistic: 'Maximum', + }); + + expect(stack.resolve(stream.metricGetRecordsLatency())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Latency', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricGetRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Records', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricGetRecordsSuccess())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Success', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricIncomingBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'IncomingBytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricIncomingRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'IncomingRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Bytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsLatency())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Latency', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsSuccess())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.Success', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsTotalRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.TotalRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsSuccessfulRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.SuccessfulRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsFailedRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.FailedRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricPutRecordsThrottledRecords())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'PutRecords.ThrottledRecords', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricReadProvisionedThroughputExceeded())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'ReadProvisionedThroughputExceeded', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricWriteProvisionedThroughputExceeded())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'WriteProvisionedThroughputExceeded', + period: fiveMinutes, + statistic: 'Average', + }); + }); + + test('allow to overide metric options', () => { + // GIVEN + const stack = new Stack(); + + const fiveMinutes = { + amount: 5, + unit: { + label: 'minutes', + isoLabel: 'M', + inMillis: 60000, + }, + }; + + // WHEN + const stream = new Stream(stack, 'MyStream'); + + // THEN + expect(stack.resolve(stream.metricGetRecordsBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Bytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricGetRecordsBytes({ + period: Duration.minutes(1), + statistic: 'Maximum', + }))).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'GetRecords.Bytes', + period: { ...fiveMinutes, amount: 1 }, + statistic: 'Maximum', + }); + + expect(stack.resolve(stream.metricIncomingBytes())).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'IncomingBytes', + period: fiveMinutes, + statistic: 'Average', + }); + + expect(stack.resolve(stream.metricIncomingBytes({ + period: Duration.minutes(1), + statistic: 'Sum', + }))).toEqual({ + dimensions: { StreamName: { Ref: 'MyStream5C050E93' } }, + namespace: 'AWS/Kinesis', + metricName: 'IncomingBytes', + period: { ...fiveMinutes, amount: 1 }, + statistic: 'Sum', + }); + }); }); diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json index 3521344439ae2..882289bd8ea55 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json @@ -64,7 +64,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index aa185d1c5ad11..dcdd6cae51708 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -74,7 +74,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index 2f03c0f5c5833..096f26f48fc15 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-kms/README.md b/packages/@aws-cdk/aws-kms/README.md index 495f42a16ec25..a576eab5aab08 100644 --- a/packages/@aws-cdk/aws-kms/README.md +++ b/packages/@aws-cdk/aws-kms/README.md @@ -40,6 +40,18 @@ key.addAlias('alias/foo'); key.addAlias('alias/bar'); ``` + +Define a key with specific key spec and key usage: + +Valid `keySpec` values depends on `keyUsage` value. + +```ts +const key = new kms.Key(this, 'MyKey', { + keySpec: kms.KeySpec.ECC_SECG_P256K1, // Default to SYMMETRIC_DEFAULT + keyUsage: kms.KeyUsage.SIGN_VERIFY // and ENCRYPT_DECRYPT +}); +``` + ## Sharing keys between stacks To use a KMS key in a different stack in the same CDK application, diff --git a/packages/@aws-cdk/aws-kms/lib/key.ts b/packages/@aws-cdk/aws-kms/lib/key.ts index 2176d28f5b5bc..bea78532bbf90 100644 --- a/packages/@aws-cdk/aws-kms/lib/key.ts +++ b/packages/@aws-cdk/aws-kms/lib/key.ts @@ -247,6 +247,85 @@ abstract class KeyBase extends Resource implements IKey { } } +/** + * The key spec, represents the cryptographic configuration of keys. + */ +export enum KeySpec { + /** + * The default key spec. + * + * Valid usage: ENCRYPT_DECRYPT + */ + SYMMETRIC_DEFAULT = 'SYMMETRIC_DEFAULT', + + /** + * RSA with 2048 bits of key. + * + * Valid usage: ENCRYPT_DECRYPT and SIGN_VERIFY + */ + RSA_2048 = 'RSA_2048', + + /** + * RSA with 3072 bits of key. + * + * Valid usage: ENCRYPT_DECRYPT and SIGN_VERIFY + */ + RSA_3072 = 'RSA_3072', + + /** + * RSA with 4096 bits of key. + * + * Valid usage: ENCRYPT_DECRYPT and SIGN_VERIFY + */ + RSA_4096 = 'RSA_4096', + + /** + * NIST FIPS 186-4, Section 6.4, ECDSA signature using the curve specified by the key and + * SHA-256 for the message digest. + * + * Valid usage: SIGN_VERIFY + */ + ECC_NIST_P256 = 'ECC_NIST_P256', + + /** + * NIST FIPS 186-4, Section 6.4, ECDSA signature using the curve specified by the key and + * SHA-384 for the message digest. + * + * Valid usage: SIGN_VERIFY + */ + ECC_NIST_P384 = 'ECC_NIST_P384', + + /** + * NIST FIPS 186-4, Section 6.4, ECDSA signature using the curve specified by the key and + * SHA-512 for the message digest. + * + * Valid usage: SIGN_VERIFY + */ + ECC_NIST_P521 = 'ECC_NIST_P521', + + /** + * Standards for Efficient Cryptography 2, Section 2.4.1, ECDSA signature on the Koblitz curve. + * + * Valid usage: SIGN_VERIFY + */ + ECC_SECG_P256K1 = 'ECC_SECG_P256K1', +} + +/** + * The key usage, represents the cryptographic operations of keys. + */ +export enum KeyUsage { + /** + * Encryption and decryption. + */ + ENCRYPT_DECRYPT = 'ENCRYPT_DECRYPT', + + /** + * Signing and verification + */ + SIGN_VERIFY = 'SIGN_VERIFY', +} + /** * Construction properties for a KMS Key object */ @@ -282,6 +361,26 @@ export interface KeyProps { */ readonly enabled?: boolean; + /** + * The cryptographic configuration of the key. The valid value depends on usage of the key. + * + * IMPORTANT: If you change this property of an existing key, the existing key is scheduled for deletion + * and a new key is created with the specified value. + * + * @default KeySpec.SYMMETRIC_DEFAULT + */ + readonly keySpec?: KeySpec; + + /** + * The cryptographic operations for which the key can be used. + * + * IMPORTANT: If you change this property of an existing key, the existing key is scheduled for deletion + * and a new key is created with the specified value. + * + * @default KeyUsage.ENCRYPT_DECRYPT + */ + readonly keyUsage?: KeyUsage; + /** * Custom policy document to attach to the KMS key. * @@ -394,6 +493,27 @@ export class Key extends KeyBase { constructor(scope: Construct, id: string, props: KeyProps = {}) { super(scope, id); + const denyLists = { + [KeyUsage.ENCRYPT_DECRYPT]: [ + KeySpec.ECC_NIST_P256, + KeySpec.ECC_NIST_P384, + KeySpec.ECC_NIST_P521, + KeySpec.ECC_SECG_P256K1, + ], + [KeyUsage.SIGN_VERIFY]: [ + KeySpec.SYMMETRIC_DEFAULT, + ], + }; + const keySpec = props.keySpec ?? KeySpec.SYMMETRIC_DEFAULT; + const keyUsage = props.keyUsage ?? KeyUsage.ENCRYPT_DECRYPT; + if (denyLists[keyUsage].includes(keySpec)) { + throw new Error(`key spec '${keySpec}' is not valid with usage '${keyUsage}'`); + } + + if (keySpec !== KeySpec.SYMMETRIC_DEFAULT && props.enableKeyRotation) { + throw new Error('key rotation cannot be enabled on asymmetric keys'); + } + const defaultKeyPoliciesFeatureEnabled = FeatureFlags.of(this).isEnabled(cxapi.KMS_DEFAULT_KEY_POLICIES); this.policy = props.policy ?? new iam.PolicyDocument(); @@ -428,6 +548,8 @@ export class Key extends KeyBase { description: props.description, enableKeyRotation: props.enableKeyRotation, enabled: props.enabled, + keySpec: props.keySpec, + keyUsage: props.keyUsage, keyPolicy: this.policy, pendingWindowInDays: pendingWindowInDays, }); diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index 32014b72b64db..9514c480d7057 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-kms/test/integ.key.expected.json b/packages/@aws-cdk/aws-kms/test/integ.key.expected.json index 6ed1da4638a2f..761498395aa0e 100644 --- a/packages/@aws-cdk/aws-kms/test/integ.key.expected.json +++ b/packages/@aws-cdk/aws-kms/test/integ.key.expected.json @@ -56,6 +56,43 @@ ] } } + }, + "AsymmetricKey26BBC514": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "KeySpec": "ECC_NIST_P256", + "KeyUsage": "SIGN_VERIFY" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-kms/test/integ.key.ts b/packages/@aws-cdk/aws-kms/test/integ.key.ts index a9c5c22d2a238..18a7da10d50a2 100644 --- a/packages/@aws-cdk/aws-kms/test/integ.key.ts +++ b/packages/@aws-cdk/aws-kms/test/integ.key.ts @@ -1,6 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; -import { Key } from '../lib'; +import { Key, KeySpec, KeyUsage } from '../lib'; const app = new App(); @@ -16,4 +16,10 @@ key.addToResourcePolicy(new iam.PolicyStatement({ key.addAlias('alias/bar'); +new Key(stack, 'AsymmetricKey', { + keySpec: KeySpec.ECC_NIST_P256, + keyUsage: KeyUsage.SIGN_VERIFY, + removalPolicy: RemovalPolicy.DESTROY, +}); + app.synth(); diff --git a/packages/@aws-cdk/aws-kms/test/key.test.ts b/packages/@aws-cdk/aws-kms/test/key.test.ts index 50c23fc265bb7..0bdb6c755d7bb 100644 --- a/packages/@aws-cdk/aws-kms/test/key.test.ts +++ b/packages/@aws-cdk/aws-kms/test/key.test.ts @@ -844,3 +844,53 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => { }); }); }); + +describe('key specs and key usages', () => { + testFutureBehavior('both usage and spec are specified', flags, cdk.App, (app) => { + const stack = new cdk.Stack(app); + new kms.Key(stack, 'Key', { keySpec: kms.KeySpec.ECC_SECG_P256K1, keyUsage: kms.KeyUsage.SIGN_VERIFY }); + + expect(stack).toHaveResourceLike('AWS::KMS::Key', { + KeySpec: 'ECC_SECG_P256K1', + KeyUsage: 'SIGN_VERIFY', + }); + }); + + testFutureBehavior('only key usage is specified', flags, cdk.App, (app) => { + const stack = new cdk.Stack(app); + new kms.Key(stack, 'Key', { keyUsage: kms.KeyUsage.ENCRYPT_DECRYPT }); + + expect(stack).toHaveResourceLike('AWS::KMS::Key', { + KeyUsage: 'ENCRYPT_DECRYPT', + }); + }); + + testFutureBehavior('only key spec is specified', flags, cdk.App, (app) => { + const stack = new cdk.Stack(app); + new kms.Key(stack, 'Key', { keySpec: kms.KeySpec.RSA_4096 }); + + expect(stack).toHaveResourceLike('AWS::KMS::Key', { + KeySpec: 'RSA_4096', + }); + }); + + testFutureBehavior('invalid combinations of key specs and key usages', flags, cdk.App, (app) => { + const stack = new cdk.Stack(app); + + expect(() => new kms.Key(stack, 'Key1', { keySpec: kms.KeySpec.ECC_NIST_P256 })) + .toThrow('key spec \'ECC_NIST_P256\' is not valid with usage \'ENCRYPT_DECRYPT\''); + expect(() => new kms.Key(stack, 'Key2', { keySpec: kms.KeySpec.ECC_SECG_P256K1, keyUsage: kms.KeyUsage.ENCRYPT_DECRYPT })) + .toThrow('key spec \'ECC_SECG_P256K1\' is not valid with usage \'ENCRYPT_DECRYPT\''); + expect(() => new kms.Key(stack, 'Key3', { keySpec: kms.KeySpec.SYMMETRIC_DEFAULT, keyUsage: kms.KeyUsage.SIGN_VERIFY })) + .toThrow('key spec \'SYMMETRIC_DEFAULT\' is not valid with usage \'SIGN_VERIFY\''); + expect(() => new kms.Key(stack, 'Key4', { keyUsage: kms.KeyUsage.SIGN_VERIFY })) + .toThrow('key spec \'SYMMETRIC_DEFAULT\' is not valid with usage \'SIGN_VERIFY\''); + }); + + testFutureBehavior('fails if key rotation enabled on asymmetric key', flags, cdk.App, (app) => { + const stack = new cdk.Stack(app); + + expect(() => new kms.Key(stack, 'Key', { enableKeyRotation: true, keySpec: kms.KeySpec.RSA_3072 })) + .toThrow('key rotation cannot be enabled on asymmetric keys'); + }); +}); diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index 729c3767d63be..406d0c43d2983 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index e41c9e294f7e8..db6745cd5540e 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -62,7 +62,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-go/.eslintrc.js b/packages/@aws-cdk/aws-lambda-go/.eslintrc.js new file mode 100644 index 0000000000000..61dd8dd001f63 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/.eslintrc.js @@ -0,0 +1,3 @@ +const baseConfig = require('cdk-build-tools/config/eslintrc'); +baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-go/.gitignore b/packages/@aws-cdk/aws-lambda-go/.gitignore new file mode 100644 index 0000000000000..5a6d23ad32d07 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/.gitignore @@ -0,0 +1,20 @@ +*.js +tsconfig.json +*.js.map +*.d.ts +*.generated.ts +dist +lib/generated/resources.ts +.jsii + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk + +!.eslintrc.js +!jest.config.js + +junit.xml diff --git a/packages/@aws-cdk/aws-lambda-go/.npmignore b/packages/@aws-cdk/aws-lambda-go/.npmignore new file mode 100644 index 0000000000000..94b89531c7268 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/.npmignore @@ -0,0 +1,27 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ diff --git a/packages/@aws-cdk/aws-lambda-go/LICENSE b/packages/@aws-cdk/aws-lambda-go/LICENSE new file mode 100644 index 0000000000000..28e4bdcec77ec --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-lambda-go/NOTICE b/packages/@aws-cdk/aws-lambda-go/NOTICE new file mode 100644 index 0000000000000..5fc3826926b5b --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-lambda-go/README.md b/packages/@aws-cdk/aws-lambda-go/README.md new file mode 100644 index 0000000000000..5fb2907b0bf7a --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/README.md @@ -0,0 +1,256 @@ +# Amazon Lambda Golang Library + + +--- + +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + +--- + + + +This library provides constructs for Golang Lambda functions. + +To use this module you will either need to have `Go` installed (`go1.11` or later) or `Docker` installed. +See [Local Bundling](#local-bundling)/[Docker Bundling](#docker-bundling) for more information. + +This module also requires that your Golang application is +using a Go version >= 1.11 and is using [Go modules](https://golang.org/ref/mod). + +## Go Function + +Define a `GoFunction`: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api' +}); +``` + +By default, if `entry` points to a directory, then the construct will assume there is a Go entry file (i.e. `main.go`). +Let's look at an example Go project: + +```bash +lamda-app +├── cmd +│   └── api +│   └── main.go +├── go.mod +├── go.sum +├── pkg +│   ├── auth +│   │   └── auth.go +│   └── middleware +│   └── middleware.go +└── vendor + ├── github.com + │   └── aws + │   └── aws-lambda-go + └── modules.txt +``` + +With the above layout I could either provide the `entry` as `lambda-app/cmd/api` or `lambda-app/cmd/api/main.go`, either will work. +When the construct builds the golang binary this will be translated `go build ./cmd/api` & `go build ./cmd/api/main.go` respectively. +The construct will figure out where it needs to run the `go build` command from, in this example it would be from +the `lambda-app` directory. It does this by determining the [mod file path](#mod-file-path), which is explained in the +next section. + +### mod file path + +The `GoFunction` tries to automatically determine your project root, that is +the root of your golang project. This is usually where the top level `go.mod` file or +`vendor` folder of your project is located. When bundling in a Docker container, the +`moduleDir` is used as the source (`/asset-input`) for the volume mounted in +the container. + +The CDK will walk up parent folders starting from +the current working directory until it finds a folder containing a `go.mod` file. + +Alternatively, you can specify the `moduleDir` prop manually. In this case you +need to ensure that this path includes `entry` and any module/dependencies used +by your function. Otherwise bundling will fail. + +## Runtime + +The `GoFunction` can be used with either the `GO_1_X` runtime or the provided runtimes (`PROVIDED`/`PROVIDED_AL2`). +By default it will use the `PROVIDED_AL2` runtime. The `GO_1_X` runtime does not support things like +[Lambda Extensions](https://docs.aws.amazon.com/lambda/latest/dg/using-extensions.html), whereas the provided runtimes do. +The [aws-lambda-go](https://github.com/aws/aws-lambda-go) library has built in support for the provided runtime as long as +you name the handler `bootstrap` (which we do by default). + +## Dependencies + +The construct will attempt to figure out how to handle the dependencies for your function. It will +do this by determining whether or not you are vendoring your dependencies. It makes this determination +by looking to see if there is a `vendor` folder at the [mod file path](#mod-file-path). + +With this information the construct can determine what commands to run. You will +generally fall into two scenarios: + +1. You are using vendoring (indicated by the presence of a `vendor` folder) + In this case `go build` will be run with `-mod=vendor` set +2. You are not using vendoring (indicated by the absence of a `vendor` folder) + If you are not vendoring then `go build` will be run without `-mod=vendor` + since the default behavior is to download dependencies + +All other properties of `lambda.Function` are supported, see also the [AWS Lambda construct library](https://github.com/aws/aws-cdk/tree/master/packages/%40aws-cdk/aws-lambda). + +## Environment + +By default the following environment variables are set for you: + +* `GOOS=linux` +* `GOARCH=amd64` +* `GO111MODULE=on` + +Use the `environment` prop to define additional environment variables when go runs: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api', + bundling: { + environment: { + HELLO: 'WORLD', + }, + }, +}); +``` + +## Local Bundling + +If `Go` is installed locally and the version is >= `go1.11` then it will be used to bundle your code in your environment. Otherwise, bundling will happen in a [Lambda compatible Docker container](https://hub.docker.com/layers/lambci/lambda/build-go1.x/images/sha256-e14dab718ed0bb06b2243825c5993e494a6969de7c01754ad7e80dacfce9b0cf?context=explore). + +For macOS the recommended approach is to install `Go` as Docker volume performance is really poor. + +`Go` can be installed by following the [installation docs](https://golang.org/doc/install). + + +## Docker + +To force bundling in a docker container even if `Go` is available in your environment, set the `forceDockerBundling` prop to `true`. This is useful if you want to make sure that your function is built in a consistent Lambda compatible environment. + +Use the `buildArgs` prop to pass build arguments when building the bundling image: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api', + bundling: { + buildArgs: { + HTTPS_PROXY: 'https://127.0.0.1:3001', + }, + }, +}); +``` + +Use the `bundling.dockerImage` prop to use a custom bundling image: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api', + bundling: { + dockerImage: cdk.DockerImage.fromBuild('/path/to/Dockerfile'), + }, +}); +``` + +Use the `bundling.goBuildFlags` prop to pass additional build flags to `go build`: + +```ts +new lambda.GoFunction(this, 'handler', { + entry: 'app/cmd/api', + bundling: { + goBuildFlags: ['-ldflags "-s -w"'], + }, +}); +``` + +## Command hooks + +It is possible to run additional commands by specifying the `commandHooks` prop: + +```ts +new lambda.GoFunction(this, 'handler', { + bundling: { + commandHooks: { + // run tests + beforeBundling(inputDir: string): string[] { + return ['go test ./cmd/api -v']; + }, + // ... + }, + }, +}); +``` + +The following hooks are available: + +* `beforeBundling`: runs before all bundling commands +* `afterBundling`: runs after all bundling commands + +They all receive the directory containing the `go.mod` file (`inputDir`) and the +directory where the bundled asset will be output (`outputDir`). They must return +an array of commands to run. Commands are chained with `&&`. + +The commands will run in the environment in which bundling occurs: inside the +container for Docker bundling or on the host OS for local bundling. + +## Additional considerations + +Depending on how you structure your Golang application, you may want to change the `assetHashType` parameter. +By default this parameter is set to `AssetHashType.OUTPUT` which means that the CDK will calculate the asset hash +(and determine whether or not your code has changed) based on the Golang executable that is created. + +If you specify `AssetHashType.SOURCE`, the CDK will calculate the asset hash by looking at the folder +that contains your `go.mod` file. If you are deploying a single Lambda function, or you want to redeploy +all of your functions if anything changes, then `AssetHashType.SOURCE` will probaby work. + + +For example, if my app looked like this: + +```bash +lamda-app +├── cmd +│   └── api +│   └── main.go +├── go.mod +├── go.sum +└── pkg +    └── auth +       └── auth.go +``` + +With this structure I would provide the `entry` as `cmd/api` which means that the CDK +will determine that the protect root is `lambda-app` (it contains the `go.mod` file). +Since I only have a single Lambda function, and any update to files within the `lambda-app` directory +should trigger a new deploy, I could specify `AssetHashType.SOURCE`. + +On the other hand, if I had a project that deployed mmultiple Lambda functions, for example: + +```bash +lamda-app +├── cmd +│   ├── api +│   │   └── main.go +│   └── anotherApi +│   └── main.go +├── go.mod +├── go.sum +└── pkg +    ├── auth +    │   └── auth.go +    └── middleware +    └── middleware.go +``` + +Then I would most likely want `AssetHashType.OUTPUT`. With `OUTPUT` +the CDK will only recognize changes if the Golang executable has changed, +and Go only includes dependencies that are used in the executable. So in this case +if `cmd/api` used the `auth` & `middleware` packages, but `cmd/anotherApi` did not, then +an update to `auth` or `middleware` would only trigger an update to the `cmd/api` Lambda +Function. diff --git a/packages/@aws-cdk/aws-lambda-go/jest.config.js b/packages/@aws-cdk/aws-lambda-go/jest.config.js new file mode 100644 index 0000000000000..33885f40aacf1 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require("cdk-build-tools/config/jest.config"); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile b/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile new file mode 100644 index 0000000000000..149d117cffdb9 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/Dockerfile @@ -0,0 +1,12 @@ +# The correct AWS SAM build image based on the runtime of the function will be +# passed as build arg. The default allows to do `docker build .` when testing. +ARG IMAGE=lambci/lambda:build-go1.x +FROM $IMAGE + +# set the GOCACHE +ENV GOCACHE=$GOPATH/.cache/go-build + +# Ensure all users can write to GOPATH +RUN chmod -R 777 $GOPATH + +CMD [ "go" ] diff --git a/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts new file mode 100644 index 0000000000000..fd320cce90aed --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/bundling.ts @@ -0,0 +1,201 @@ +import * as os from 'os'; +import * as path from 'path'; +import { AssetCode, Code, Runtime } from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import { BundlingOptions } from './types'; +import { exec, findUp, getGoBuildVersion } from './util'; + +/** + * Options for bundling + */ +export interface BundlingProps extends BundlingOptions { + /** + * Directory containing your go.mod file + * + * This will accept either a directory path containing a `go.mod` file + * or a filepath to your `go.mod` file (i.e. `path/to/go.mod`). + * + * This will be used as the source of the volume mounted in the Docker + * container and will be the directory where it will run `go build` from. + * + * @default - the path is found by walking up parent directories searching for + * a `go.mod` file from the location of `entry` + */ + readonly moduleDir: string; + + /** + * The path to the folder or file that contains the main application entry point files for the project. + * + * This accepts either a path to a directory or file. + * + * If a directory path is provided then it will assume there is a Go entry file (i.e. `main.go`) and + * will construct the build command using the directory path. + * + * For example, if you provide the entry as: + * + * entry: 'my-lambda-app/cmd/api' + * + * Then the `go build` command would be: + * + * `go build ./cmd/api` + * + * If a path to a file is provided then it will use the filepath in the build command. + * + * For example, if you provide the entry as: + * + * entry: 'my-lambda-app/cmd/api/main.go' + * + * Then the `go build` command would be: + * + * `go build ./cmd/api/main.go` + */ + readonly entry: string; + + /** + * The runtime of the lambda function + */ + readonly runtime: Runtime; +} + +/** + * Bundling + */ +export class Bundling implements cdk.BundlingOptions { + + public static bundle(options: BundlingProps): AssetCode { + const bundling = new Bundling(options); + + return Code.fromAsset(path.dirname(options.moduleDir), { + assetHashType: options.assetHashType ?? cdk.AssetHashType.OUTPUT, + assetHash: options.assetHash, + bundling: { + image: bundling.image, + command: bundling.command, + environment: bundling.environment, + local: bundling.local, + }, + }); + } + + public static clearRunsLocallyCache(): void { // for tests + this.runsLocally = undefined; + } + + private static runsLocally?: boolean; + + // Core bundling options + public readonly image: cdk.DockerImage; + public readonly command: string[]; + public readonly environment?: { [key: string]: string }; + public readonly local?: cdk.ILocalBundling; + + private readonly relativeEntryPath: string; + + constructor(private readonly props: BundlingProps) { + Bundling.runsLocally = Bundling.runsLocally + ?? getGoBuildVersion() + ?? false; + + const projectRoot = path.dirname(props.moduleDir); + this.relativeEntryPath = `./${path.relative(projectRoot, path.resolve(props.entry))}`; + + const cgoEnabled = props.cgoEnabled ? '1' : '0'; + + const environment = { + CGO_ENABLED: cgoEnabled, + GO111MODULE: 'on', + GOARCH: 'amd64', + GOOS: 'linux', + ...props.environment, + }; + + // Docker bundling + const shouldBuildImage = props.forcedDockerBundling || !Bundling.runsLocally; + this.image = shouldBuildImage + ? props.dockerImage ?? cdk.DockerImage.fromBuild(path.join(__dirname, '../lib'), { + buildArgs: { + ...props.buildArgs ?? {}, + IMAGE: Runtime.GO_1_X.bundlingImage.image, // always use the GO_1_X build image + }, + }) + : cdk.DockerImage.fromRegistry('dummy'); // Do not build if we don't need to + + const bundlingCommand = this.createBundlingCommand(cdk.AssetStaging.BUNDLING_INPUT_DIR, cdk.AssetStaging.BUNDLING_OUTPUT_DIR); + this.command = ['bash', '-c', bundlingCommand]; + this.environment = environment; + + // Local bundling + if (!props.forcedDockerBundling) { // only if Docker is not forced + + const osPlatform = os.platform(); + const createLocalCommand = (outputDir: string) => this.createBundlingCommand(projectRoot, outputDir, osPlatform); + + this.local = { + tryBundle(outputDir: string) { + if (Bundling.runsLocally == false) { + process.stderr.write('go build cannot run locally. Switching to Docker bundling.\n'); + return false; + } + + const localCommand = createLocalCommand(outputDir); + exec( + osPlatform === 'win32' ? 'cmd' : 'bash', + [ + osPlatform === 'win32' ? '/c' : '-c', + localCommand, + ], + { + env: { ...process.env, ...environment ?? {} }, + stdio: [ // show output + 'ignore', // ignore stdio + process.stderr, // redirect stdout to stderr + 'inherit', // inherit stderr + ], + cwd: path.dirname(props.moduleDir), + windowsVerbatimArguments: osPlatform === 'win32', + }, + ); + return true; + }, + }; + } + } + + public createBundlingCommand(inputDir: string, outputDir: string, osPlatform: NodeJS.Platform = 'linux'): string { + const pathJoin = osPathJoin(osPlatform); + + const hasVendor = findUp('vendor', path.dirname(this.props.entry)); + + const goBuildCommand: string = [ + 'go', 'build', + hasVendor ? '-mod=vendor': '', + '-o', `${pathJoin(outputDir, 'bootstrap')}`, + `${this.props.goBuildFlags ? this.props.goBuildFlags.join(' ') : ''}`, + `${this.relativeEntryPath.replace(/\\/g, '/')}`, + ].filter(c => !!c).join(' '); + + return chain([ + ...this.props.commandHooks?.beforeBundling(inputDir, outputDir) ?? [], + goBuildCommand, + ...this.props.commandHooks?.afterBundling(inputDir, outputDir) ?? [], + ]); + } +} + +/** + * Platform specific path join + */ +function osPathJoin(platform: NodeJS.Platform) { + return function(...paths: string[]): string { + const joined = path.join(...paths); + // If we are on win32 but need posix style paths + if (os.platform() === 'win32' && platform !== 'win32') { + return joined.replace(/\\/g, '/'); + } + return joined; + }; +} + +function chain(commands: string[]): string { + return commands.filter(c => !!c).join(' && '); +} diff --git a/packages/@aws-cdk/aws-lambda-go/lib/function.ts b/packages/@aws-cdk/aws-lambda-go/lib/function.ts new file mode 100644 index 0000000000000..3b915e859cef3 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/function.ts @@ -0,0 +1,121 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as lambda from '@aws-cdk/aws-lambda'; +import { Bundling } from './bundling'; +import { BundlingOptions } from './types'; +import { findUp } from './util'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/** + * Properties for a GolangFunction + */ +export interface GoFunctionProps extends lambda.FunctionOptions { + /** + * The path to the folder or file that contains the main application entry point files for the project. + * + * This accepts either a path to a directory or file. + * + * If a directory path is provided then it will assume there is a Go entry file (i.e. `main.go`) and + * will construct the build command using the directory path. + * + * For example, if you provide the entry as: + * + * entry: 'my-lambda-app/cmd/api' + * + * Then the `go build` command would be: + * + * `go build ./cmd/api` + * + * If a path to a file is provided then it will use the filepath in the build command. + * + * For example, if you provide the entry as: + * + * entry: 'my-lambda-app/cmd/api/main.go' + * + * Then the `go build` command would be: + * + * `go build ./cmd/api/main.go` + */ + readonly entry: string; + + /** + * The runtime environment. Only runtimes of the Golang family and provided family are supported. + * + * @default lambda.Runtime.PROVIDED_AL2 + */ + readonly runtime?: lambda.Runtime; + + /** + * Directory containing your go.mod file + * + * This will accept either a directory path containing a `go.mod` file + * or a filepath to your `go.mod` file (i.e. `path/to/go.mod`). + * + * This will be used as the source of the volume mounted in the Docker + * container and will be the directory where it will run `go build` from. + * + * @default - the path is found by walking up parent directories searching for + * a `go.mod` file from the location of `entry` + */ + readonly moduleDir?: string; + + /** + * Bundling options + * + * @default - use default bundling options + */ + readonly bundling?: BundlingOptions; +} + +/** + * A Golang Lambda function + */ +export class GoFunction extends lambda.Function { + constructor(scope: Construct, id: string, props: GoFunctionProps) { + if (props.runtime && (props.runtime.family !== lambda.RuntimeFamily.GO && props.runtime.family != lambda.RuntimeFamily.OTHER)) { + throw new Error('Only `go` and `provided` runtimes are supported.'); + } + + const entry = path.resolve(props.entry); + + // Find the project root + let moduleDir: string; + if (props.moduleDir) { + const parsedModuleDir = path.parse(props.moduleDir); + if (parsedModuleDir.base && parsedModuleDir.ext && parsedModuleDir.base === 'go.mod') { + if (!fs.existsSync(props.moduleDir)) { + throw new Error(`go.mod file at ${props.moduleDir} doesn't exist`); + } + } else if (parsedModuleDir.base && parsedModuleDir.ext && parsedModuleDir.base != 'go.mod') { + throw new Error('moduleDir is specifying a file that is not go.mod'); + } else if (!fs.existsSync(path.join(props.moduleDir, 'go.mod'))) { + throw new Error(`go.mod file at ${props.moduleDir} doesn't exist`); + } + moduleDir = props.moduleDir; + } else { + const modFile = findUp('go.mod', entry); + if (!modFile) { + throw new Error ('Cannot find go.mod. Please specify it with `moduleDir`.'); + } + moduleDir = modFile; + } + + const runtime = props.runtime ?? lambda.Runtime.PROVIDED_AL2; + + super(scope, id, { + ...props, + runtime, + code: Bundling.bundle({ + ...props.bundling ?? {}, + entry, + runtime, + moduleDir, + }), + handler: 'bootstrap', // setting name to bootstrap so that the 'provided' runtime can also be used + }); + } +} + diff --git a/packages/@aws-cdk/aws-lambda-go/lib/index.ts b/packages/@aws-cdk/aws-lambda-go/lib/index.ts new file mode 100644 index 0000000000000..f1fdff0ce2e4c --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/index.ts @@ -0,0 +1,2 @@ +export * from './function'; +export * from './types'; diff --git a/packages/@aws-cdk/aws-lambda-go/lib/types.ts b/packages/@aws-cdk/aws-lambda-go/lib/types.ts new file mode 100644 index 0000000000000..bcd334809be33 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/types.ts @@ -0,0 +1,132 @@ +import { AssetHashType, DockerImage } from '@aws-cdk/core'; + +/** + * Bundling options + */ +export interface BundlingOptions { + /** + * Environment variables defined when go runs. + * + * @default - no environment variables are defined. + */ + readonly environment?: { [key: string]: string; }; + + /** + * Force bundling in a Docker container even if local bundling is + * possible. + * + * @default - false + */ + readonly forcedDockerBundling?: boolean; + + /** + * A custom bundling Docker image. + * + * @default - use the Docker image provided by @aws-cdk/aws-lambda-go + */ + readonly dockerImage?: DockerImage; + + /** + * List of additional flags to use while building. + * + * For example: + * ['ldflags "-s -w"'] + * + * @default - none + */ + readonly goBuildFlags?: string[]; + + /** + * Build arguments to pass when building the bundling image. + * + * @default - no build arguments are passed + */ + readonly buildArgs?: { [key:string] : string }; + + /** + * Determines how the asset hash is calculated. Assets will + * get rebuilt and uploaded only if their hash has changed. + * + * If the asset hash is set to `OUTPUT` (default), the hash is calculated + * after bundling. This means that any change in the output will cause + * the asset to be invalidated and uploaded. Bear in mind that the + * go binary that is output can be different depending on the environment + * that it was compiled in. If you want to control when the output is changed + * it is recommended that you use immutable build images such as + * `public.ecr.aws/bitnami/golang:1.16.3-debian-10-r16`. + * + * If the asset hash is set to `SOURCE`, then only changes to the source + * directory will cause the asset to rebuild. If your go project has multiple + * Lambda functions this means that an update to any one function could cause + * all the functions to be rebuilt and uploaded. + * + * @default - AssetHashType.OUTPUT. If `assetHash` is also specified, + * the default is `CUSTOM`. + */ + readonly assetHashType?: AssetHashType; + + /** + * Specify a custom hash for this asset. If `assetHashType` is set it must + * be set to `AssetHashType.CUSTOM`. For consistency, this custom hash will + * be SHA256 hashed and encoded as hex. The resulting hash will be the asset + * hash. + * + * NOTE: the hash is used in order to identify a specific revision of the asset, and + * used for optimizing and caching deployment activities related to this asset such as + * packaging, uploading to Amazon S3, etc. If you chose to customize the hash, you will + * need to make sure it is updated every time the asset changes, or otherwise it is + * possible that some deployments will not be invalidated. + * + * @default - based on `assetHashType` + */ + readonly assetHash?: string; + + /** + * Command hooks + * + * @default - do not run additional commands + */ + readonly commandHooks?: ICommandHooks; + + /** + * Whether or not to enable cgo during go build + * + * This will set the CGO_ENABLED environment variable + * + * @default - false + */ + readonly cgoEnabled?: boolean; +} + +/** + * Command hooks + * + * These commands will run in the environment in which bundling occurs: inside + * the container for Docker bundling or on the host OS for local bundling. + * + * Commands are chained with `&&`. + * + * @example + * { + * // Run tests prior to bundling + * beforeBundling(inputDir: string, outputDir: string): string[] { + * return [`go test -mod=vendor ./...`]; + * } + * // ... + * } + */ +export interface ICommandHooks { + /** + * Returns commands to run before bundling. + * + * Commands are chained with `&&`. + */ + beforeBundling(inputDir: string, outputDir: string): string[]; + + /** + * Returns commands to run after bundling. + * + * Commands are chained with `&&`. + */ + afterBundling(inputDir: string, outputDir: string): string[]; +} diff --git a/packages/@aws-cdk/aws-lambda-go/lib/util.ts b/packages/@aws-cdk/aws-lambda-go/lib/util.ts new file mode 100644 index 0000000000000..84ff188848f55 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/lib/util.ts @@ -0,0 +1,58 @@ +import { spawnSync, SpawnSyncOptions } from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; + +const GO_VERSION_REGEX = /go([0-9]{1,4})+?(\.([0-9]{1,4}))+?(\.([0-9]{1,4}))?/; + +export function getGoBuildVersion(): boolean | undefined { + try { + const go = spawnSync('go', ['version']); + if (go.status !== 0 || go.error) { + return undefined; + } + const goVersion = go.stdout.toString().split(' ')[2].match(GO_VERSION_REGEX); + if (!goVersion || goVersion[3] <= '11') { + return undefined; + } else { + return true; + } + } catch (err) { + return undefined; + } +} + +/** + * Spawn sync with error handling + */ +export function exec(cmd: string, args: string[], options?: SpawnSyncOptions) { + const proc = spawnSync(cmd, args, options); + + if (proc.error) { + throw proc.error; + } + + if (proc.status !== 0) { + if (proc.stdout || proc.stderr) { + throw new Error(`[Status ${proc.status}] stdout: ${proc.stdout?.toString().trim()}\n\n\nstderr: ${proc.stderr?.toString().trim()}`); + } + throw new Error(`${cmd} exited with status ${proc.status}`); + } + + return proc; +} + +export function findUp(name: string, directory: string = process.cwd()): string | undefined { + const absoluteDirectory = path.resolve(directory); + + const file = path.join(directory, name); + if (fs.existsSync(file)) { + return file; + } + + const { root } = path.parse(absoluteDirectory); + if (absoluteDirectory == root) { + return undefined; + } + + return findUp(name, path.dirname(absoluteDirectory)); +} diff --git a/packages/@aws-cdk/aws-lambda-go/package.json b/packages/@aws-cdk/aws-lambda-go/package.json new file mode 100644 index 0000000000000..c9d8899a3a0a8 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/package.json @@ -0,0 +1,102 @@ +{ + "name": "@aws-cdk/aws-lambda-go", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS Lambda in Golang", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.services.lambda.go", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "lambda-go" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.AWS.Lambda.Go", + "packageId": "Amazon.CDK.AWS.Lambda.Go", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.aws-lambda-go", + "module": "aws_cdk.aws_lambda_go", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ] + } + }, + "projectReferences": true + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-lambda-go" + }, + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "build+test+package": "yarn build+test && yarn package", + "build+test": "yarn build && yarn test", + "compat": "cdk-compat", + "rosetta:extract": "yarn --silent jsii-rosetta extract" + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "lambda" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@types/jest": "^26.0.23", + "@aws-cdk/aws-ec2": "0.0.0", + "cdk-build-tools": "0.0.0", + "cdk-integ-tools": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "homepage": "https://github.com/aws/aws-cdk", + "peerDependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "experimental", + "awscdkio": { + "announce": false + }, + "nozem": { + "ostools": ["docker"] + }, + "cdk-build": { + "jest": true + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts new file mode 100644 index 0000000000000..c6a743a422719 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts @@ -0,0 +1,316 @@ +import * as child_process from 'child_process'; +import * as os from 'os'; +import * as path from 'path'; +import { Code, Runtime } from '@aws-cdk/aws-lambda'; +import { AssetHashType, DockerImage } from '@aws-cdk/core'; +import { Bundling } from '../lib/bundling'; +import * as util from '../lib/util'; + +jest.mock('@aws-cdk/aws-lambda'); +const fromAssetMock = jest.spyOn(DockerImage, 'fromBuild'); +let getGoBuildVersionMock = jest.spyOn(util, 'getGoBuildVersion'); + +beforeEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + Bundling.clearRunsLocallyCache(); + getGoBuildVersionMock.mockReturnValue(true); + fromAssetMock.mockReturnValue({ + image: 'built-image', + cp: () => 'built-image', + run: () => {}, + toJSON: () => 'build-image', + }); +}); + +const moduleDir = '/project/go.mod'; +const entry = '/project/cmd/api'; + +test('bundling', () => { + Bundling.bundle({ + entry, + runtime: Runtime.GO_1_X, + moduleDir, + forcedDockerBundling: true, + environment: { + KEY: 'value', + }, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(moduleDir), { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + environment: { + KEY: 'value', + CGO_ENABLED: '0', + GO111MODULE: 'on', + GOARCH: 'amd64', + GOOS: 'linux', + }, + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./cmd/api', + ].join(' && '), + ], + }), + }); +}); + +test('bundling with file as entry', () => { + Bundling.bundle({ + entry: '/project/main.go', + runtime: Runtime.GO_1_X, + moduleDir, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./main.go', + ].join(' && '), + ], + }), + }); +}); + +test('bundling with file in subdirectory as entry', () => { + Bundling.bundle({ + entry: '/project/cmd/api/main.go', + runtime: Runtime.GO_1_X, + moduleDir, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./cmd/api/main.go', + ].join(' && '), + ], + }), + }); +}); + +test('bundling with file other than main.go in subdirectory as entry', () => { + Bundling.bundle({ + entry: '/project/cmd/api/api.go', + runtime: Runtime.GO_1_X, + moduleDir, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./cmd/api/api.go', + ].join(' && '), + ], + }), + }); +}); + +test('go with Windows paths', () => { + const osPlatformMock = jest.spyOn(os, 'platform').mockReturnValue('win32'); + Bundling.bundle({ + entry: 'C:\\my-project\\cmd\\api', + runtime: Runtime.GO_1_X, + moduleDir: 'C:\\my-project\\go.mod', + forcedDockerBundling: true, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: expect.arrayContaining([ + expect.stringContaining('cmd/api'), + ]), + }), + })); + osPlatformMock.mockRestore(); +}); + +test('with Docker build args', () => { + Bundling.bundle({ + entry, + runtime: Runtime.GO_1_X, + moduleDir, + forcedDockerBundling: true, + buildArgs: { + HELLO: 'WORLD', + }, + }); + expect(fromAssetMock).toHaveBeenCalledWith(expect.stringMatching(/lib$/), expect.objectContaining({ + buildArgs: expect.objectContaining({ + HELLO: 'WORLD', + }), + })); +}); + +test('Local bundling', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('go version go1.15 linux/amd64'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + const bundler = new Bundling({ + moduleDir, + entry, + environment: { + KEY: 'value', + }, + runtime: Runtime.PROVIDED_AL2, + }); + + expect(bundler.local).toBeDefined(); + + const tryBundle = bundler.local?.tryBundle('/outdir', { image: Runtime.GO_1_X.bundlingDockerImage }); + expect(tryBundle).toBe(true); + + expect(spawnSyncMock).toHaveBeenCalledWith( + 'bash', + expect.arrayContaining(['-c', expect.stringContaining('cmd/api')]), + expect.objectContaining({ + env: expect.objectContaining({ KEY: 'value' }), + cwd: expect.stringContaining('/project'), + }), + ); + + // Docker image is not built + expect(fromAssetMock).not.toHaveBeenCalled(); +}); + +test('Incorrect go version', () => { + getGoBuildVersionMock.mockReturnValueOnce(false); + + const bundler = new Bundling({ + entry, + moduleDir, + runtime: Runtime.PROVIDED_AL2, + }); + + const tryBundle = bundler.local?.tryBundle('/outdir', { image: Runtime.GO_1_X.bundlingDockerImage }); + + expect(tryBundle).toBe(false); +}); + + +test('Custom bundling docker image', () => { + Bundling.bundle({ + entry, + moduleDir, + runtime: Runtime.GO_1_X, + forcedDockerBundling: true, + dockerImage: DockerImage.fromRegistry('my-custom-image'), + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + image: { image: 'my-custom-image' }, + }), + }); +}); + +test('Go build flags can be passed', () => { + Bundling.bundle({ + entry, + runtime: Runtime.GO_1_X, + moduleDir, + environment: { + KEY: 'value', + }, + goBuildFlags: ['-ldflags "-s -w"'], + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + environment: { + KEY: 'value', + CGO_ENABLED: '0', + GO111MODULE: 'on', + GOARCH: 'amd64', + GOOS: 'linux', + }, + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap -ldflags "-s -w" ./cmd/api', + ].join(' && '), + ], + }), + }); +}); + +test('AssetHashType can be specified', () => { + Bundling.bundle({ + entry, + runtime: Runtime.GO_1_X, + moduleDir, + environment: { + KEY: 'value', + }, + assetHashType: AssetHashType.OUTPUT, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith('/project', { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + environment: { + KEY: 'value', + CGO_ENABLED: '0', + GO111MODULE: 'on', + GOARCH: 'amd64', + GOOS: 'linux', + }, + command: [ + 'bash', '-c', + [ + 'go build -o /asset-output/bootstrap ./cmd/api', + ].join(' && '), + ], + }), + }); +}); + + +test('with command hooks', () => { + Bundling.bundle({ + entry, + moduleDir, + runtime: Runtime.PROVIDED_AL2, + commandHooks: { + beforeBundling(inputDir: string, outputDir: string): string[] { + return [ + `echo hello > ${inputDir}/a.txt`, + `cp ${inputDir}/a.txt ${outputDir}`, + ]; + }, + afterBundling(inputDir: string, outputDir: string): string[] { + return [`cp ${inputDir}/b.txt ${outputDir}/txt`]; + }, + }, + }); + + expect(Code.fromAsset).toHaveBeenCalledWith(path.dirname(moduleDir), { + assetHashType: AssetHashType.OUTPUT, + bundling: expect.objectContaining({ + command: [ + 'bash', '-c', + expect.stringMatching(/^echo hello > \/asset-input\/a.txt && cp \/asset-input\/a.txt \/asset-output && .+ && cp \/asset-input\/b.txt \/asset-output\/txt$/), + ], + }), + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts b/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts new file mode 100644 index 0000000000000..d619d9f0fb91d --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/docker.test.ts @@ -0,0 +1,15 @@ +import { spawnSync } from 'child_process'; +import * as path from 'path'; + +beforeAll(() => { + spawnSync('docker', ['build', '--build-arg', 'IMAGE=public.ecr.aws/bitnami/golang:1.15', '-t', 'golang', path.join(__dirname, '../lib')]); +}); + +test('golang is available', async () => { + const proc = spawnSync('docker', [ + 'run', 'golang', + 'sh', '-c', + 'go version', + ]); + expect(proc.status).toEqual(0); +}); diff --git a/packages/@aws-cdk/aws-lambda-go/test/function.test.ts b/packages/@aws-cdk/aws-lambda-go/test/function.test.ts new file mode 100644 index 0000000000000..472dc39fc769f --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/function.test.ts @@ -0,0 +1,147 @@ +import '@aws-cdk/assert-internal/jest'; +import * as path from 'path'; +import { Runtime } from '@aws-cdk/aws-lambda'; +import { Stack } from '@aws-cdk/core'; +import { GoFunction } from '../lib'; +import { Bundling } from '../lib/bundling'; + +jest.mock('../lib/bundling', () => { + return { + Bundling: { + bundle: jest.fn().mockReturnValue({ + bind: () => { + return { s3Location: 'code' }; + }, + bindToResource: () => { return; }, + }), + }, + }; +}); + +let stack: Stack; +beforeEach(() => { + stack = new Stack(); + jest.clearAllMocks(); +}); + +test('GoFunction with defaults', () => { + // WHEN + new GoFunction(stack, 'handler', { + entry: path.join(__dirname, 'lambda-handler-vendor/cmd/api'), + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringMatching(/@aws-cdk\/aws-lambda-go\/test\/lambda-handler-vendor\/cmd\/api$/), + })); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + Runtime: 'provided.al2', + }); +}); + +test('GoFunction with using provided runtime', () => { + // WHEN + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + runtime: Runtime.PROVIDED, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringMatching(/@aws-cdk\/aws-lambda-go\/test\/lambda-handler-vendor\/cmd\/api$/), + })); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + Runtime: 'provided', + }); +}); + +test('GoFunction with using golang runtime', () => { + // WHEN + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + runtime: Runtime.GO_1_X, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringMatching(/@aws-cdk\/aws-lambda-go\/test\/lambda-handler-vendor\/cmd\/api$/), + })); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + Runtime: 'go1.x', + }); +}); + +test('GoFunction with container env vars', () => { + // WHEN + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + bundling: { + environment: { + KEY: 'VALUE', + }, + }, + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + environment: { + KEY: 'VALUE', + }, + })); +}); + +test('throws with the wrong runtime family', () => { + expect(() => new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + runtime: Runtime.PYTHON_3_8, + })).toThrow(/Only `go` and `provided` runtimes are supported/); +}); + +test('resolves entry to an absolute path', () => { + // WHEN + new GoFunction(stack, 'fn', { + entry: 'test/lambda-handler-vendor/cmd/api/main.go', + }); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringMatching(/@aws-cdk\/aws-lambda-go\/test\/lambda-handler-vendor\/cmd\/api\/main.go$/), + })); +}); + +test('throws with no existing go.mod file', () => { + expect(() => new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + moduleDir: '/does/not/exist/go.mod', + })).toThrow(/go.mod file at \/does\/not\/exist\/go.mod doesn't exist/); +}); + +test('throws with incorrect moduleDir file', () => { + expect(() => new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + moduleDir: '/does/not/exist.mod', + })).toThrow(/moduleDir is specifying a file that is not go.mod/); +}); + +test('custom moduleDir can be used', () => { + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + moduleDir: 'test/lambda-handler-vendor', + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + }); +}); + +test('custom moduleDir with file path can be used', () => { + new GoFunction(stack, 'handler', { + entry: 'test/lambda-handler-vendor/cmd/api', + moduleDir: 'test/lambda-handler-vendor/go.mod', + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Handler: 'bootstrap', + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-go/test/integ.function.expected.json b/packages/@aws-cdk/aws-lambda-go/test/integ.function.expected.json new file mode 100644 index 0000000000000..9ae6cc08830e8 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/integ.function.expected.json @@ -0,0 +1,103 @@ +{ + "Resources": { + "gohandlerdockerServiceRole70394790": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "gohandlerdockerAE04F1B8": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3Bucket62A8237E" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50" + } + ] + } + ] + } + ] + ] + } + }, + "Role": { + "Fn::GetAtt": [ + "gohandlerdockerServiceRole70394790", + "Arn" + ] + }, + "Handler": "bootstrap", + "Runtime": "provided.al2" + }, + "DependsOn": [ + "gohandlerdockerServiceRole70394790" + ] + } + }, + "Parameters": { + "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3Bucket62A8237E": { + "Type": "String", + "Description": "S3 bucket for asset \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + }, + "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1S3VersionKey1C4F3B50": { + "Type": "String", + "Description": "S3 key for asset version \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + }, + "AssetParameters4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1ArtifactHashBE683488": { + "Type": "String", + "Description": "Artifact hash for asset \"4702fc8f2fac1855e6700e59222ef0ebbeaf11eba75c66af9f2e216e312b16b1\"" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-go/test/integ.function.ts b/packages/@aws-cdk/aws-lambda-go/test/integ.function.ts new file mode 100644 index 0000000000000..093597339e8b5 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/integ.function.ts @@ -0,0 +1,32 @@ +import * as path from 'path'; +import { App, DockerImage, Stack, StackProps } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as lambda from '../lib'; + +/* + * Stack verification steps: + * * aws lambda invoke --function-name --invocation-type Event --payload '"OK"' response.json + */ + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + new lambda.GoFunction(this, 'go-handler-docker', { + entry: path.join(__dirname, 'lambda-handler-vendor/cmd/api'), + bundling: { + dockerImage: DockerImage.fromBuild(path.join(__dirname, '../lib'), { + buildArgs: { + IMAGE: 'public.ecr.aws/bitnami/golang:1.16.3-debian-10-r16', + }, + }), + forcedDockerBundling: true, + goBuildFlags: ['-mod=readonly', '-ldflags "-s -w"'], + }, + }); + } +} + +const app = new App(); +new TestStack(app, 'cdk-integ-lambda-golang'); +app.synth(); diff --git a/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/cmd/api/main.go b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/cmd/api/main.go new file mode 100644 index 0000000000000..3dc0f71439536 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/cmd/api/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "context" + "fmt" + + "github.com/aws/aws-lambda-go/lambda" +) + +type MyEvent struct { + Name string `json:"name"` +} + +func HandleRequest(ctx context.Context, name MyEvent) (string, error) { + return fmt.Sprintf("Hello %s!", name.Name), nil +} + +func main() { + lambda.Start(HandleRequest) +} diff --git a/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.mod b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.mod new file mode 100644 index 0000000000000..24ac2f8c41afa --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.mod @@ -0,0 +1,10 @@ +module aws-lambda-golang + +go 1.16 + +require ( + github.com/aws/aws-lambda-go v1.19.1 + github.com/kr/text v0.2.0 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect +) diff --git a/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.sum b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.sum new file mode 100644 index 0000000000000..94f7ebf0f685e --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/lambda-handler-vendor/go.sum @@ -0,0 +1,32 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aws/aws-lambda-go v1.19.1 h1:5iUHbIZ2sG6Yq/J1IN3sWm3+vAB1CWwhI21NffLNuNI= +github.com/aws/aws-lambda-go v1.19.1/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/packages/@aws-cdk/aws-lambda-go/test/util.test.ts b/packages/@aws-cdk/aws-lambda-go/test/util.test.ts new file mode 100644 index 0000000000000..dc2b9d350658e --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-go/test/util.test.ts @@ -0,0 +1,157 @@ +import * as child_process from 'child_process'; +import * as os from 'os'; +import * as path from 'path'; +import { exec, findUp, getGoBuildVersion } from '../lib/util'; + +beforeEach(() => { + jest.clearAllMocks(); +}); + + +describe('findUp', () => { + test('Starting at process.cwd()', () => { + expect(findUp('README.md')).toMatch(/aws-lambda-go\/README.md$/); + }); + + test('Non existing file', () => { + expect(findUp('non-existing-file.unknown')).toBe(undefined); + }); + + test('Starting at a specific path', () => { + expect(findUp('util.test.ts', path.join(__dirname, 'integ-handlers'))).toMatch(/aws-lambda-go\/test\/util.test.ts$/); + }); + + test('Non existing file starting at a non existing relative path', () => { + expect(findUp('not-to-be-found.txt', 'non-existing/relative/path')).toBe(undefined); + }); + + test('Starting at a relative path', () => { + expect(findUp('util.test.ts', 'test/integ-handlers')).toMatch(/aws-lambda-go\/test\/util.test.ts$/); + }); +}); + +describe('exec', () => { + test('normal execution', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + const proc = exec( + 'cmd', + ['arg1', 'arg2'], + { env: { KEY: 'value' } }, + ); + + expect(spawnSyncMock).toHaveBeenCalledWith( + 'cmd', + ['arg1', 'arg2'], + { env: { KEY: 'value' } }, + ); + expect(proc.stdout.toString()).toBe('stdout'); + + spawnSyncMock.mockRestore(); + }); + + test('non zero status', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 999, + stderr: Buffer.from('error occured'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(() => exec('cmd', ['arg1', 'arg2'])).toThrow('error occured'); + + spawnSyncMock.mockRestore(); + }); + + test('with error', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + error: new Error('bad error'), + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(() => exec('cmd', ['arg1', 'arg2'])).toThrow(new Error('bad error')); + + spawnSyncMock.mockRestore(); + }); +}); + +describe('getGoBuildVersion', () => { + test('returns the version', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('go version go1.15 linux/amd64'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(getGoBuildVersion()).toBe(true); + expect(spawnSyncMock).toHaveBeenCalledWith('go', ['version']); + + spawnSyncMock.mockRestore(); + }); + + test('returns undefined on non zero status', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 127, // status error + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(getGoBuildVersion()).toBeUndefined(); + + spawnSyncMock.mockRestore(); + }); + + test('returns undefined on error', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + error: new Error('bad error'), + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + + expect(getGoBuildVersion()).toBeUndefined(); + + spawnSyncMock.mockRestore(); + }); + + test('Windows', () => { + const spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('go version go1.15 windows/amd64'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + const osPlatformMock = jest.spyOn(os, 'platform').mockReturnValue('win32'); + + expect(getGoBuildVersion()).toBe(true); + expect(spawnSyncMock).toHaveBeenCalledWith('go', expect.any(Array)); + + spawnSyncMock.mockRestore(); + osPlatformMock.mockRestore(); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/README.md b/packages/@aws-cdk/aws-lambda-nodejs/README.md index 57da4b190cca6..7a1662dc26fb2 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/README.md +++ b/packages/@aws-cdk/aws-lambda-nodejs/README.md @@ -11,8 +11,6 @@ This library provides constructs for Node.js Lambda functions. -To use this module, you will need to have Docker installed. - ## Node.js Function Define a `NodejsFunction`: diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts index afa3d93d21a9b..49e9b40b5cd5d 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as lambda from '@aws-cdk/aws-lambda'; import { Bundling } from './bundling'; import { BundlingOptions } from './types'; -import { callsites, findUp, LockFile, nodeMajorVersion } from './util'; +import { callsites, findUp, LockFile } from './util'; // keep this import separate from other imports to reduce chance for merge conflicts with v2-main // eslint-disable-next-line no-duplicate-imports, import/order @@ -34,8 +34,7 @@ export interface NodejsFunctionProps extends lambda.FunctionOptions { * The runtime environment. Only runtimes of the Node.js family are * supported. * - * @default - `NODEJS_14_X` if `process.versions.node` >= '14.0.0', - * `NODEJS_12_X` otherwise. + * @default Runtime.NODEJS_14_X */ readonly runtime?: lambda.Runtime; @@ -105,10 +104,7 @@ export class NodejsFunction extends lambda.Function { // Entry and defaults const entry = path.resolve(findEntry(id, props.entry)); const handler = props.handler ?? 'handler'; - const defaultRunTime = nodeMajorVersion() >= 14 - ? lambda.Runtime.NODEJS_14_X - : lambda.Runtime.NODEJS_12_X; - const runtime = props.runtime ?? defaultRunTime; + const runtime = props.runtime ?? lambda.Runtime.NODEJS_14_X; super(scope, id, { ...props, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts index f74030f7376d1..206941f71f66d 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts @@ -32,13 +32,6 @@ export function callsites(): CallSite[] { return stack as unknown as CallSite[]; } -/** - * Returns the major version of node installation - */ -export function nodeMajorVersion(): number { - return parseInt(process.versions.node.split('.')[0], 10); -} - /** * Find a file by walking up parent directories */ diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index 29e2cc9a1291b..ae5a2e85cfc8b 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -62,12 +62,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-ec2": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "delay": "5.0.0", - "esbuild": "^0.11.10", + "esbuild": "^0.11.20", "pkglint": "0.0.0", "@aws-cdk/assert-internal": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts index a02dcbe449663..cc4544ec6e732 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/function.test.ts @@ -7,7 +7,6 @@ import { CodeConfig, Runtime } from '@aws-cdk/aws-lambda'; import { Stack } from '@aws-cdk/core'; import { NodejsFunction } from '../lib'; import { Bundling } from '../lib/bundling'; -import { nodeMajorVersion } from '../lib/util'; jest.mock('../lib/bundling', () => { return { @@ -41,13 +40,9 @@ test('NodejsFunction with .ts handler', () => { entry: expect.stringContaining('function.test.handler1.ts'), // Automatically finds .ts handler file })); - const runtime = nodeMajorVersion() >= 14 - ? Runtime.NODEJS_14_X - : Runtime.NODEJS_12_X; - expect(stack).toHaveResource('AWS::Lambda::Function', { Handler: 'index.handler', - Runtime: runtime.name, + Runtime: 'nodejs14.x', }); }); diff --git a/packages/@aws-cdk/aws-lambda-python/package.json b/packages/@aws-cdk/aws-lambda-python/package.json index f00f41ba10094..e324128af4845 100644 --- a/packages/@aws-cdk/aws-lambda-python/package.json +++ b/packages/@aws-cdk/aws-lambda-python/package.json @@ -62,7 +62,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 82f0cb7279aae..3fdc26ada0d5e 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -75,8 +75,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", - "@types/aws-lambda": "^8.10.75", + "@types/jest": "^26.0.23", + "@types/aws-lambda": "^8.10.76", "@types/lodash": "^4.14.168", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-licensemanager/package.json b/packages/@aws-cdk/aws-licensemanager/package.json index 45b7e2a40f953..18956a928aaf5 100644 --- a/packages/@aws-cdk/aws-licensemanager/package.json +++ b/packages/@aws-cdk/aws-licensemanager/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index 1646e493109be..3d1ce13174cf7 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -62,7 +62,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index 8eeec6ce861fe..7af39bdef71e5 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -71,7 +71,7 @@ "license": "Apache-2.0", "devDependencies": { "@types/nodeunit": "^0.0.31", - "@types/aws-lambda": "^8.10.75", + "@types/aws-lambda": "^8.10.76", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", "aws-sdk-mock": "^5.1.0", diff --git a/packages/@aws-cdk/aws-lookoutmetrics/package.json b/packages/@aws-cdk/aws-lookoutmetrics/package.json index b28a28779e6a9..c2971b0d20209 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/package.json +++ b/packages/@aws-cdk/aws-lookoutmetrics/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/assert-internal": "0.0.0", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-lookoutvision/package.json b/packages/@aws-cdk/aws-lookoutvision/package.json index 5e5f54a21f4e9..0834033c7ae3b 100644 --- a/packages/@aws-cdk/aws-lookoutvision/package.json +++ b/packages/@aws-cdk/aws-lookoutvision/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-macie/package.json b/packages/@aws-cdk/aws-macie/package.json index ca320f425e7c0..c6a8387bfe91e 100644 --- a/packages/@aws-cdk/aws-macie/package.json +++ b/packages/@aws-cdk/aws-macie/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index 32ffe6fa6dc69..af0f11adc1349 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediaconnect/package.json b/packages/@aws-cdk/aws-mediaconnect/package.json index 366a1f7d920f2..b0c34a4125d98 100644 --- a/packages/@aws-cdk/aws-mediaconnect/package.json +++ b/packages/@aws-cdk/aws-mediaconnect/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index e40f564b6ee8c..9ec2a9930fdc7 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index 03c89879e7fc3..b25d9bf03a805 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediapackage/package.json b/packages/@aws-cdk/aws-mediapackage/package.json index cf97b77e47300..74a784a91dcaf 100644 --- a/packages/@aws-cdk/aws-mediapackage/package.json +++ b/packages/@aws-cdk/aws-mediapackage/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index 2e42e37e56ab7..00ff06822b6f3 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-msk/README.md b/packages/@aws-cdk/aws-msk/README.md index 51d93453f1eef..c0e6982799545 100644 --- a/packages/@aws-cdk/aws-msk/README.md +++ b/packages/@aws-cdk/aws-msk/README.md @@ -21,8 +21,96 @@ -This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. +[Amazon MSK](https://aws.amazon.com/msk/) is a fully managed service that makes it easy for you to build and run applications that use Apache Kafka to process streaming data. + +The following example creates an MSK Cluster. ```ts import * as msk from '@aws-cdk/aws-msk'; + +const cluster = new Cluster(this, 'Cluster', { + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, +}); +``` + +## Allowing Connections + +To control who can access the Cluster, use the `.connections` attribute. For a list of ports used by MSK, refer to the [MSK documentation](https://docs.aws.amazon.com/msk/latest/developerguide/client-access.html#port-info). + +```typescript +import * as msk from "@aws-cdk/aws-msk" +import * as ec2 from "@aws-cdk/aws-ec2" + +const cluster = new msk.Cluster(this, "Cluster", {...}) + +cluster.connections.allowFrom( + ec2.Peer.ipv4("1.2.3.4/8"), + ec2.Port.tcp(2181) +) +cluster.connections.allowFrom( + ec2.Peer.ipv4("1.2.3.4/8"), + ec2.Port.tcp(9094) +) +``` + +## Cluster Endpoints + +You can use the following attributes to get a list of the Kafka broker or ZooKeeper node endpoints + +```typescript +new cdk.CfnOutput(this, 'BootstrapBrokers', { value: cluster.bootstrapBrokers }); +new cdk.CfnOutput(this, 'BootstrapBrokersTls', { value: cluster.bootstrapBrokersTls }); +new cdk.CfnOutput(this, 'BootstrapBrokersSaslScram', { value: cluster.bootstrapBrokersSaslScram }); +new cdk.CfnOutput(this, 'ZookeeperConnection', { value: cluster.zookeeperConnectionString }); +new cdk.CfnOutput(this, 'ZookeeperConnectionTls', { value: cluster.zookeeperConnectionStringTls }); +``` + +## Importing an existing Cluster + +To import an existing MSK cluster into your CDK app use the `.fromClusterArn()` method. + +```typescript +const cluster = msk.Cluster.fromClusterArn(this, 'Cluster', 'arn:aws:kafka:us-west-2:1234567890:cluster/a-cluster/11111111-1111-1111-1111-111111111111-1') +``` + +## Client Authentication + +### TLS + +To enable client authentication with TLS set the `certificateAuthorityArns` property to reference your ACM Private CA. [More info on Private CAs.](https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html) + +```typescript +import * as msk from "@aws-cdk/aws-msk" + +const cluster = new msk.Cluster(this, 'Cluster', { + ... + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.TLS, + }, + clientAuthentication: msk.ClientAuthentication.tls({ + certificateAuthorityArns: [ + 'arn:aws:acm-pca:us-west-2:1234567890:certificate-authority/11111111-1111-1111-1111-111111111111', + ], + }), + }); +}); +``` + +### SASL/SCRAM + +Enable client authentication with SASL/SCRAM: + +```typescript +import * as msk from "@aws-cdk/aws-msk" + +const cluster = new msk.cluster(this, "cluster", { + ... + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.TLS, + }, + clientAuthentication: msk.ClientAuthentication.sasl({ + scram: true, + }), +}) ``` diff --git a/packages/@aws-cdk/aws-msk/lib/cluster-version.ts b/packages/@aws-cdk/aws-msk/lib/cluster-version.ts new file mode 100644 index 0000000000000..0d3b511aae59e --- /dev/null +++ b/packages/@aws-cdk/aws-msk/lib/cluster-version.ts @@ -0,0 +1,63 @@ +/** + * Kafka cluster version + */ +export class KafkaVersion { + /** + * Kafka version 1.1.1 + */ + public static readonly V1_1_1 = KafkaVersion.of('1.1.1'); + + /** + * Kafka version 2.2.1 + */ + public static readonly V2_2_1 = KafkaVersion.of('2.2.1'); + + /** + * Kafka version 2.3.1 + */ + public static readonly V2_3_1 = KafkaVersion.of('2.3.1'); + + /** + * Kafka version 2.4.1 + */ + public static readonly V2_4_1_1 = KafkaVersion.of('2.4.1.1'); + + /** + * Kafka version 2.5.1 + */ + public static readonly V2_5_1 = KafkaVersion.of('2.5.1'); + + /** + * Kafka version 2.6.0 + */ + public static readonly V2_6_0 = KafkaVersion.of('2.6.0'); + + /** + * Kafka version 2.6.1 + */ + public static readonly V2_6_1 = KafkaVersion.of('2.6.1'); + + /** + * Kafka version 2.7.0 + */ + public static readonly V2_7_0 = KafkaVersion.of('2.7.0'); + + /** + * Kafka version 2.8.0 + */ + public static readonly V2_8_0 = KafkaVersion.of('2.8.0'); + + /** + * Custom cluster version + * @param version custom version number + */ + public static of(version: string) { + return new KafkaVersion(version); + } + + /** + * + * @param version cluster version number + */ + private constructor(public readonly version: string) {} +} diff --git a/packages/@aws-cdk/aws-msk/lib/cluster.ts b/packages/@aws-cdk/aws-msk/lib/cluster.ts index 313bd3de5b107..75ec20ac9360d 100644 --- a/packages/@aws-cdk/aws-msk/lib/cluster.ts +++ b/packages/@aws-cdk/aws-msk/lib/cluster.ts @@ -1,34 +1,769 @@ -import { IResource, Resource } from '@aws-cdk/core'; -import { Construct } from 'constructs'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; +import * as logs from '@aws-cdk/aws-logs'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; +import * as core from '@aws-cdk/core'; +import * as cr from '@aws-cdk/custom-resources'; +import * as constructs from 'constructs'; +import { addressOf } from 'constructs/lib/private/uniqueid'; +import { CfnCluster, KafkaVersion } from './'; /** - * Represents an MSK cluster + * Represents a MSK Cluster */ -export interface ICluster extends IResource { +export interface ICluster extends core.IResource, ec2.IConnectable { /** - * the ARN of the MSK cluster + * The ARN of cluster. + * + * @attribute */ readonly clusterArn: string; + + /** + * The physical name of the cluster. + * + * @attribute + */ + readonly clusterName: string; +} + +/** + * A new or imported MSK Cluster. + */ +abstract class ClusterBase extends core.Resource implements ICluster { + public abstract readonly clusterArn: string; + public abstract readonly clusterName: string; + /** @internal */ + protected _connections: ec2.Connections | undefined; + + /** Manages connections for the cluster */ + public get connections(): ec2.Connections { + if (!this._connections) { + throw new Error('An imported Cluster cannot manage its security groups'); + } + return this._connections; + } } /** - * An MSK cluster + * Properties for a MSK Cluster */ -export class Cluster { +export interface ClusterProps { + /** + * The physical name of the cluster. + */ + readonly clusterName: string; + /** + * The version of Apache Kafka. + */ + readonly kafkaVersion: KafkaVersion; /** - * Creates a Cluster construct that represents an existing MSK cluster. - * @param scope - * @param id - * @param clusterArn + * Number of Apache Kafka brokers deployed in each Availability Zone. + * + * @default 1 */ - public static fromClusterArn(scope: Construct, id: string, clusterArn: string): ICluster { - class Imported extends Resource implements ICluster { - public readonly clusterArn: string; - constructor() { - super(scope, id); - this.clusterArn = clusterArn; + readonly numberOfBrokerNodes?: number; + /** + * Defines the virtual networking environment for this cluster. + * Must have at least 2 subnets in two different AZs. + */ + readonly vpc: ec2.IVpc; + /** + * Where to place the nodes within the VPC. + * Amazon MSK distributes the broker nodes evenly across the subnets that you specify. + * The subnets that you specify must be in distinct Availability Zones. + * Client subnets can't be in Availability Zone us-east-1e. + * + * @default - the Vpc default strategy if not specified. + */ + readonly vpcSubnets?: ec2.SubnetSelection; + /** + * The EC2 instance type that you want Amazon MSK to use when it creates your brokers. + * + * @see https://docs.aws.amazon.com/msk/latest/developerguide/msk-create-cluster.html#broker-instance-types + * @default kafka.m5.large + */ + readonly instanceType?: ec2.InstanceType; + /** + * The AWS security groups to associate with the elastic network interfaces in order to specify who can + * connect to and communicate with the Amazon MSK cluster. + * + * @default - create new security group + */ + readonly securityGroups?: ec2.ISecurityGroup[]; + /** + * Information about storage volumes attached to MSK broker nodes. + * + * @default - 1000 GiB EBS volume + */ + readonly ebsStorageInfo?: EbsStorageInfo; + /** + * The Amazon MSK configuration to use for the cluster. + * + * @default - none + */ + readonly configurationInfo?: ClusterConfigurationInfo; + /** + * Cluster monitoring configuration. + * + * @default - DEFAULT monitoring level + */ + readonly monitoring?: MonitoringConfiguration; + /** + * Configure your MSK cluster to send broker logs to different destination types. + * + * @default - disabled + */ + readonly logging?: BrokerLogging; + /** + * Config details for encryption in transit. + * + * @default - enabled + */ + readonly encryptionInTransit?: EncryptionInTransitConfig; + /** + * Configuration properties for client authentication. + * MSK supports using private TLS certificates or SASL/SCRAM to authenticate the identity of clients. + * + * @default - disabled + */ + readonly clientAuthentication?: ClientAuthentication; + /** + * What to do when this resource is deleted from a stack. + * + * @default RemovalPolicy.RETAIN + */ + readonly removalPolicy?: core.RemovalPolicy; +} + +/** + * EBS volume information. + */ +export interface EbsStorageInfo { + /** + * The size in GiB of the EBS volume for the data drive on each broker node. + * + * @default 1000 + */ + readonly volumeSize?: number; + /** + * The AWS KMS key for encrypting data at rest. + * + * @default Uses AWS managed CMK (aws/kafka) + */ + readonly encryptionKey?: kms.IKey; +} + +/** + * The Amazon MSK configuration to use for the cluster. + * Note: There is currently no Cloudformation Resource to create a Configuration + */ +export interface ClusterConfigurationInfo { + /** + * The Amazon Resource Name (ARN) of the MSK configuration to use. + * For example, arn:aws:kafka:us-east-1:123456789012:configuration/example-configuration-name/abcdabcd-1234-abcd-1234-abcd123e8e8e-1. + */ + readonly arn: string; + /** + * The revision of the Amazon MSK configuration to use. + */ + readonly revision: number; +} + +/** + * The level of monitoring for the MSK cluster + * + * @see https://docs.aws.amazon.com/msk/latest/developerguide/monitoring.html#metrics-details + */ +export enum ClusterMonitoringLevel { + /** + * Default metrics are the essential metrics to monitor. + */ + DEFAULT = 'DEFAULT', + /** + * Per Broker metrics give you metrics at the broker level. + */ + PER_BROKER = 'PER_BROKER', + /** + * Per Topic Per Broker metrics help you understand volume at the topic level. + */ + PER_TOPIC_PER_BROKER = 'PER_TOPIC_PER_BROKER', + /** + * Per Topic Per Partition metrics help you understand consumer group lag at the topic partition level. + */ + PER_TOPIC_PER_PARTITION = 'PER_TOPIC_PER_PARTITION', +} + +/** + * Monitoring Configuration + */ +export interface MonitoringConfiguration { + /** + * Specifies the level of monitoring for the MSK cluster. + * + * @default DEFAULT + */ + readonly clusterMonitoringLevel?: ClusterMonitoringLevel; + /** + * Indicates whether you want to enable or disable the JMX Exporter. + * + * @default false + */ + readonly enablePrometheusJmxExporter?: boolean; + /** + * Indicates whether you want to enable or disable the Prometheus Node Exporter. + * + * You can use the Prometheus Node Exporter to get CPU and disk metrics for the broker nodes. + * + * @default false + */ + readonly enablePrometheusNodeExporter?: boolean; +} + +/** + * Configuration details related to broker logs. + */ +export interface BrokerLogging { + /** + * The Kinesis Data Firehose delivery stream that is the destination for broker logs. + * + * @default - disabled + */ + readonly firehoseDeliveryStreamName?: string; + /** + * The CloudWatch Logs group that is the destination for broker logs. + * + * @default - disabled + */ + readonly cloudwatchLogGroup?: logs.ILogGroup; + /** + * Details of the Amazon S3 destination for broker logs. + * + * @default - disabled + */ + readonly s3?: S3LoggingConfiguration; +} + +/** + * Details of the Amazon S3 destination for broker logs. + */ +export interface S3LoggingConfiguration { + /** + * The S3 bucket that is the destination for broker logs. + */ + readonly bucket: s3.IBucket; + /** + * The S3 prefix that is the destination for broker logs. + * + * @default - no prefix + */ + readonly prefix?: string; +} + +/** + * Indicates the encryption setting for data in transit between clients and brokers. + */ +export enum ClientBrokerEncryption { + /** + * TLS means that client-broker communication is enabled with TLS only. + */ + TLS = 'TLS', + /** + * TLS_PLAINTEXT means that client-broker communication is enabled for both TLS-encrypted, as well as plaintext data. + */ + TLS_PLAINTEXT = 'TLS_PLAINTEXT', + /** + * PLAINTEXT means that client-broker communication is enabled in plaintext only. + */ + PLAINTEXT = 'PLAINTEXT', +} + +/** + * The settings for encrypting data in transit. + * + * @see https://docs.aws.amazon.com/msk/latest/developerguide/msk-encryption.html#msk-encryption-in-transit + */ +export interface EncryptionInTransitConfig { + /** + * Indicates the encryption setting for data in transit between clients and brokers. + * + * @default - TLS + */ + readonly clientBroker?: ClientBrokerEncryption; + /** + * Indicates that data communication among the broker nodes of the cluster is encrypted. + * + * @default true + */ + readonly enableInCluster?: boolean; +} + +/** + * SASL authentication properties + */ +export interface SaslAuthProps { + /** + * Enable SASL/SCRAM authentication. + * + * @default false + */ + readonly scram?: boolean; + /** + * KMS Key to encrypt SASL/SCRAM secrets. + * + * You must use a customer master key (CMK) when creating users in secrets manager. + * You cannot use a Secret with Amazon MSK that uses the default Secrets Manager encryption key. + * + * @default - CMK will be created with alias msk/{clusterName}/sasl/scram + */ + readonly key?: kms.IKey; +} + +/** + * TLS authentication properties + */ +export interface TlsAuthProps { + /** + * List of ACM Certificate Authorities to enable TLS authentication. + * + * @default - none + */ + readonly certificateAuthorityArns?: string[]; +} + +/** + * Configuration properties for client authentication. + */ +export class ClientAuthentication { + /** + * SASL authentication + */ + public static sasl(props: SaslAuthProps): ClientAuthentication { + return new ClientAuthentication(props, undefined); + } + + /** + * TLS authentication + */ + public static tls(props: TlsAuthProps): ClientAuthentication { + return new ClientAuthentication(undefined, props); + } + + /** + * @param saslProps - properties for SASL authentication + * @param tlsProps - properties for TLS authentication + */ + private constructor( + public readonly saslProps?: SaslAuthProps, + public readonly tlsProps?: TlsAuthProps, + ) {} +} + +/** + * Create a MSK Cluster. + * + * @resource AWS::MSK::Cluster + */ +export class Cluster extends ClusterBase { + /** + * Reference an existing cluster, defined outside of the CDK code, by name. + */ + public static fromClusterArn( + scope: constructs.Construct, + id: string, + clusterArn: string, + ): ICluster { + class Import extends ClusterBase { + public readonly clusterArn = clusterArn; + public readonly clusterName = core.Fn.select(1, core.Fn.split('/', clusterArn)); // ['arn:partition:kafka:region:account-id', clusterName, clusterId] + } + + return new Import(scope, id); + } + + public readonly clusterArn: string; + public readonly clusterName: string; + /** Key used to encrypt SASL/SCRAM users */ + public readonly saslScramAuthenticationKey?: kms.IKey; + private _clusterDescription?: cr.AwsCustomResource; + private _clusterBootstrapBrokers?: cr.AwsCustomResource; + + constructor(scope: constructs.Construct, id: string, props: ClusterProps) { + super(scope, id, { + physicalName: props.clusterName, + }); + + const subnetSelection = props.vpc.selectSubnets(props.vpcSubnets); + + this._connections = new ec2.Connections({ + securityGroups: props.securityGroups ?? [ + new ec2.SecurityGroup(this, 'SecurityGroup', { + description: 'MSK security group', + vpc: props.vpc, + }), + ], + }); + + if (subnetSelection.subnets.length < 2) { + throw Error( + `Cluster requires at least 2 subnets, got ${subnetSelection.subnets.length}`, + ); + } + + if ( + !core.Token.isUnresolved(props.clusterName) && + !/^[a-zA-Z0-9]+$/.test(props.clusterName) && + props.clusterName.length > 64 + ) { + throw Error( + 'The cluster name must only contain alphanumeric characters and have a maximum length of 64 characters.' + + `got: '${props.clusterName}. length: ${props.clusterName.length}'`, + ); + } + + if ( + props.encryptionInTransit?.clientBroker === + ClientBrokerEncryption.PLAINTEXT && + props.clientAuthentication + ) { + throw Error( + 'To enable client authentication, you must enabled TLS-encrypted traffic between clients and brokers.', + ); + } else if ( + props.encryptionInTransit?.clientBroker === + ClientBrokerEncryption.TLS_PLAINTEXT && + props.clientAuthentication?.saslProps?.scram + ) { + throw Error( + 'To enable SASL/SCRAM authentication, you must only allow TLS-encrypted traffic between clients and brokers.', + ); + } + + const volumeSize = + props.ebsStorageInfo?.volumeSize ?? 1000; + // Minimum: 1 GiB, maximum: 16384 GiB + if (volumeSize < 1 || volumeSize > 16384) { + throw Error( + 'EBS volume size should be in the range 1-16384', + ); + } + + const instanceType = props.instanceType + ? this.mskInstanceType(props.instanceType) + : this.mskInstanceType( + ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE), + ); + + const encryptionAtRest = props.ebsStorageInfo?.encryptionKey + ? { + dataVolumeKmsKeyId: + props.ebsStorageInfo.encryptionKey.keyId, } + : undefined; // MSK will create the managed key + + const encryptionInTransit = { + clientBroker: + props.encryptionInTransit?.clientBroker ?? + ClientBrokerEncryption.TLS, + inCluster: props.encryptionInTransit?.enableInCluster ?? true, + }; + + const openMonitoring = + props.monitoring?.enablePrometheusJmxExporter || + props.monitoring?.enablePrometheusNodeExporter + ? { + prometheus: { + jmxExporter: props.monitoring?.enablePrometheusJmxExporter + ? { enabledInBroker: true } + : undefined, + nodeExporter: props.monitoring + ?.enablePrometheusNodeExporter + ? { enabledInBroker: true } + : undefined, + }, + } + : undefined; + + const loggingInfo = { + brokerLogs: { + cloudWatchLogs: { + enabled: + props.logging?.cloudwatchLogGroup !== undefined, + logGroup: + props.logging?.cloudwatchLogGroup?.logGroupName, + }, + firehose: { + enabled: + props.logging?.firehoseDeliveryStreamName !== + undefined, + deliveryStream: + props.logging?.firehoseDeliveryStreamName, + }, + s3: { + enabled: props.logging?.s3?.bucket !== undefined, + bucket: props.logging?.s3?.bucket.bucketName, + prefix: props.logging?.s3?.prefix, + }, + }, + }; + + if ( + props.clientAuthentication?.saslProps?.scram && + props.clientAuthentication?.saslProps?.key === undefined + ) { + this.saslScramAuthenticationKey = new kms.Key(this, 'SASLKey', { + description: + 'Used for encrypting MSK secrets for SASL/SCRAM authentication.', + alias: `msk/${props.clusterName}/sasl/scram`, + }); + + // https://docs.aws.amazon.com/kms/latest/developerguide/services-secrets-manager.html#asm-policies + this.saslScramAuthenticationKey.addToResourcePolicy( + new iam.PolicyStatement({ + sid: + 'Allow access through AWS Secrets Manager for all principals in the account that are authorized to use AWS Secrets Manager', + principals: [new iam.Anyone()], + actions: [ + 'kms:Encrypt', + 'kms:Decrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + 'kms:CreateGrant', + 'kms:DescribeKey', + ], + resources: ['*'], + conditions: { + StringEquals: { + 'kms:ViaService': `secretsmanager.${core.Stack.of(this).region}.amazonaws.com`, + 'kms:CallerAccount': core.Stack.of(this).account, + }, + }, + }), + ); + } + const clientAuthentication = props.clientAuthentication + ? { + sasl: props.clientAuthentication?.saslProps?.scram + ? { + scram: { + enabled: props.clientAuthentication?.saslProps.scram, + }, + } + : undefined, + tls: props.clientAuthentication?.tlsProps?.certificateAuthorityArns + ? { + certificateAuthorityArnList: + props.clientAuthentication?.tlsProps + ?.certificateAuthorityArns, + } + : undefined, + } + : undefined; + + const resource = new CfnCluster(this, 'Resource', { + clusterName: props.clusterName, + kafkaVersion: props.kafkaVersion.version, + numberOfBrokerNodes: + props.numberOfBrokerNodes !== undefined ? + subnetSelection.availabilityZones.length * props.numberOfBrokerNodes : subnetSelection.availabilityZones.length, + brokerNodeGroupInfo: { + instanceType, + clientSubnets: subnetSelection.subnetIds, + securityGroups: this.connections.securityGroups.map( + (group) => group.securityGroupId, + ), + storageInfo: { + ebsStorageInfo: { + volumeSize: volumeSize, + }, + }, + }, + encryptionInfo: { + encryptionAtRest, + encryptionInTransit, + }, + configurationInfo: props.configurationInfo, + enhancedMonitoring: props.monitoring?.clusterMonitoringLevel, + openMonitoring: openMonitoring, + loggingInfo: loggingInfo, + clientAuthentication: clientAuthentication, + }); + + this.clusterName = this.getResourceNameAttribute( + core.Fn.select(1, core.Fn.split('/', resource.ref)), + ); + this.clusterArn = resource.ref; + + resource.applyRemovalPolicy(props.removalPolicy, { + default: core.RemovalPolicy.RETAIN, + }); + } + + private mskInstanceType(instanceType: ec2.InstanceType): string { + return `kafka.${instanceType.toString()}`; + } + + /** + * Get the ZooKeeper Connection string + * + * Uses a Custom Resource to make an API call to `describeCluster` using the Javascript SDK + * + * @param responseField Field to return from API call. eg. ZookeeperConnectString, ZookeeperConnectStringTls + * @returns - The connection string to use to connect to the Apache ZooKeeper cluster. + */ + private _zookeeperConnectionString(responseField: string): string { + if (!this._clusterDescription) { + this._clusterDescription = new cr.AwsCustomResource(this, 'ZookeeperConnect', { + onUpdate: { + service: 'Kafka', + action: 'describeCluster', + parameters: { + ClusterArn: this.clusterArn, + }, + physicalResourceId: cr.PhysicalResourceId.of( + 'ZooKeeperConnectionString', + ), + }, + policy: cr.AwsCustomResourcePolicy.fromSdkCalls({ + resources: [this.clusterArn], + }), + }); + } + return this._clusterDescription.getResponseField(`ClusterInfo.${responseField}`); + } + + /** + * Get the ZooKeeper Connection string + * + * Uses a Custom Resource to make an API call to `describeCluster` using the Javascript SDK + * + * @returns - The connection string to use to connect to the Apache ZooKeeper cluster. + */ + public get zookeeperConnectionString(): string { + return this._zookeeperConnectionString('ZookeeperConnectString'); + } + + /** + * Get the ZooKeeper Connection string for a TLS enabled cluster + * + * Uses a Custom Resource to make an API call to `describeCluster` using the Javascript SDK + * + * @returns - The connection string to use to connect to zookeeper cluster on TLS port. + */ + public get zookeeperConnectionStringTls(): string { + return this._zookeeperConnectionString('ZookeeperConnectStringTls'); + } + + /** + * Get the list of brokers that a client application can use to bootstrap + * + * Uses a Custom Resource to make an API call to `getBootstrapBrokers` using the Javascript SDK + * + * @param responseField Field to return from API call. eg. BootstrapBrokerStringSaslScram, BootstrapBrokerString + * @returns - A string containing one or more hostname:port pairs. + */ + private _bootstrapBrokers(responseField: string): string { + if (!this._clusterBootstrapBrokers) { + this._clusterBootstrapBrokers = new cr.AwsCustomResource(this, `BootstrapBrokers${responseField}`, { + onUpdate: { + service: 'Kafka', + action: 'getBootstrapBrokers', + parameters: { + ClusterArn: this.clusterArn, + }, + physicalResourceId: cr.PhysicalResourceId.of('BootstrapBrokers'), + }, + policy: cr.AwsCustomResourcePolicy.fromSdkCalls({ + resources: [this.clusterArn], + }), + }); + } + return this._clusterBootstrapBrokers.getResponseField(responseField); + + } + /** + * Get the list of brokers that a client application can use to bootstrap + * + * Uses a Custom Resource to make an API call to `getBootstrapBrokers` using the Javascript SDK + * + * @returns - A string containing one or more hostname:port pairs. + */ + public get bootstrapBrokers(): string { + return this._bootstrapBrokers('BootstrapBrokerString'); + } + + /** + * Get the list of brokers that a TLS authenticated client application can use to bootstrap + * + * Uses a Custom Resource to make an API call to `getBootstrapBrokers` using the Javascript SDK + * + * @returns - A string containing one or more DNS names (or IP) and TLS port pairs. + */ + public get bootstrapBrokersTls(): string { + return this._bootstrapBrokers('BootstrapBrokerStringTls'); + } + + /** + * Get the list of brokers that a SASL/SCRAM authenticated client application can use to bootstrap + * + * Uses a Custom Resource to make an API call to `getBootstrapBrokers` using the Javascript SDK + * + * @returns - A string containing one or more dns name (or IP) and SASL SCRAM port pairs. + */ + public get bootstrapBrokersSaslScram(): string { + return this._bootstrapBrokers('BootstrapBrokerStringSaslScram'); + } + + /** + * A list of usersnames to register with the cluster. The password will automatically be generated using Secrets + * Manager and the { username, password } JSON object stored in Secrets Manager as `AmazonMSK_username`. + * + * Must be using the SASL/SCRAM authentication mechanism. + * + * @param usernames - username(s) to register with the cluster + */ + public addUser(...usernames: string[]): void { + if (this.saslScramAuthenticationKey) { + const MSK_SECRET_PREFIX = 'AmazonMSK_'; // Required + const secrets = usernames.map( + (username) => + new secretsmanager.Secret(this, `KafkaUser${username}`, { + secretName: `${MSK_SECRET_PREFIX}${this.clusterName}_${username}`, + generateSecretString: { + secretStringTemplate: JSON.stringify({ username }), + generateStringKey: 'password', + }, + encryptionKey: this.saslScramAuthenticationKey, + }), + ); + + new cr.AwsCustomResource(this, `BatchAssociateScramSecrets${addressOf(usernames)}`, { + onUpdate: { + service: 'Kafka', + action: 'batchAssociateScramSecret', + parameters: { + ClusterArn: this.clusterArn, + SecretArnList: secrets.map((secret) => secret.secretArn), + }, + physicalResourceId: cr.PhysicalResourceId.of('CreateUsers'), + }, + policy: cr.AwsCustomResourcePolicy.fromStatements([ + new iam.PolicyStatement({ + actions: ['kms:CreateGrant'], + resources: [this.saslScramAuthenticationKey?.keyArn], + }), + new iam.PolicyStatement({ + actions: ['kafka:BatchAssociateScramSecret'], + resources: [this.clusterArn], + }), + ]), + }); + } else { + throw Error( + 'Cannot create users if an authentication KMS key has not been created/provided.', + ); } - return new Imported(); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-msk/lib/index.ts b/packages/@aws-cdk/aws-msk/lib/index.ts index 9cc4acdc7d61f..137ac89880f81 100644 --- a/packages/@aws-cdk/aws-msk/lib/index.ts +++ b/packages/@aws-cdk/aws-msk/lib/index.ts @@ -1,3 +1,5 @@ export * from './cluster'; +export * from './cluster-version'; + // AWS::MSK CloudFormation Resources: export * from './msk.generated'; diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index d03a956690dbd..ae1b9cbdbf3f9 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -73,18 +73,34 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", + "cdk-integ-tools": "0.0.0", "pkglint": "0.0.0", + "jest": "^26.6.3", "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", + "@aws-cdk/aws-secretsmanager": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-msk/test/__snapshots__/cluster.test.js.snap b/packages/@aws-cdk/aws-msk/test/__snapshots__/cluster.test.js.snap new file mode 100644 index 0000000000000..9343682f8918b --- /dev/null +++ b/packages/@aws-cdk/aws-msk/test/__snapshots__/cluster.test.js.snap @@ -0,0 +1,486 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MSK Cluster Snapshot test with all values set 1`] = ` +Object { + "Resources": Object { + "Vpc8378EB38": Object { + "Properties": Object { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc", + }, + ], + }, + "Type": "AWS::EC2::VPC", + }, + "VpcIGWD7BA715C": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc", + }, + ], + }, + "Type": "AWS::EC2::InternetGateway", + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": Object { + "Properties": Object { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": Object { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA", + }, + "RouteTableId": Object { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500", + }, + }, + "Type": "AWS::EC2::Route", + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": Object { + "Properties": Object { + "RouteTableId": Object { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500", + }, + "SubnetId": Object { + "Ref": "VpcPrivateSubnet1Subnet536B997A", + }, + }, + "Type": "AWS::EC2::SubnetRouteTableAssociation", + }, + "VpcPrivateSubnet1RouteTableB2C5B500": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PrivateSubnet1", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::RouteTable", + }, + "VpcPrivateSubnet1Subnet536B997A": Object { + "Properties": Object { + "AvailabilityZone": Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::GetAZs": "", + }, + ], + }, + "CidrBlock": "10.0.128.0/18", + "MapPublicIpOnLaunch": false, + "Tags": Array [ + Object { + "Key": "aws-cdk:subnet-name", + "Value": "Private", + }, + Object { + "Key": "aws-cdk:subnet-type", + "Value": "Private", + }, + Object { + "Key": "Name", + "Value": "Default/Vpc/PrivateSubnet1", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::Subnet", + }, + "VpcPrivateSubnet2DefaultRoute060D2087": Object { + "Properties": Object { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": Object { + "Ref": "VpcPublicSubnet2NATGateway9182C01D", + }, + "RouteTableId": Object { + "Ref": "VpcPrivateSubnet2RouteTableA678073B", + }, + }, + "Type": "AWS::EC2::Route", + }, + "VpcPrivateSubnet2RouteTableA678073B": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PrivateSubnet2", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::RouteTable", + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": Object { + "Properties": Object { + "RouteTableId": Object { + "Ref": "VpcPrivateSubnet2RouteTableA678073B", + }, + "SubnetId": Object { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1", + }, + }, + "Type": "AWS::EC2::SubnetRouteTableAssociation", + }, + "VpcPrivateSubnet2Subnet3788AAA1": Object { + "Properties": Object { + "AvailabilityZone": Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::GetAZs": "", + }, + ], + }, + "CidrBlock": "10.0.192.0/18", + "MapPublicIpOnLaunch": false, + "Tags": Array [ + Object { + "Key": "aws-cdk:subnet-name", + "Value": "Private", + }, + Object { + "Key": "aws-cdk:subnet-type", + "Value": "Private", + }, + Object { + "Key": "Name", + "Value": "Default/Vpc/PrivateSubnet2", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::Subnet", + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": Object { + "DependsOn": Array [ + "VpcVPCGWBF912B6E", + ], + "Properties": Object { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": Object { + "Ref": "VpcIGWD7BA715C", + }, + "RouteTableId": Object { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E", + }, + }, + "Type": "AWS::EC2::Route", + }, + "VpcPublicSubnet1EIPD7E02669": Object { + "Properties": Object { + "Domain": "vpc", + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet1", + }, + ], + }, + "Type": "AWS::EC2::EIP", + }, + "VpcPublicSubnet1NATGateway4D7517AA": Object { + "Properties": Object { + "AllocationId": Object { + "Fn::GetAtt": Array [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId", + ], + }, + "SubnetId": Object { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4", + }, + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet1", + }, + ], + }, + "Type": "AWS::EC2::NatGateway", + }, + "VpcPublicSubnet1RouteTable6C95E38E": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet1", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::RouteTable", + }, + "VpcPublicSubnet1RouteTableAssociation97140677": Object { + "Properties": Object { + "RouteTableId": Object { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E", + }, + "SubnetId": Object { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4", + }, + }, + "Type": "AWS::EC2::SubnetRouteTableAssociation", + }, + "VpcPublicSubnet1Subnet5C2D37C4": Object { + "Properties": Object { + "AvailabilityZone": Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::GetAZs": "", + }, + ], + }, + "CidrBlock": "10.0.0.0/18", + "MapPublicIpOnLaunch": true, + "Tags": Array [ + Object { + "Key": "aws-cdk:subnet-name", + "Value": "Public", + }, + Object { + "Key": "aws-cdk:subnet-type", + "Value": "Public", + }, + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet1", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::Subnet", + }, + "VpcPublicSubnet2DefaultRoute97F91067": Object { + "DependsOn": Array [ + "VpcVPCGWBF912B6E", + ], + "Properties": Object { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": Object { + "Ref": "VpcIGWD7BA715C", + }, + "RouteTableId": Object { + "Ref": "VpcPublicSubnet2RouteTable94F7E489", + }, + }, + "Type": "AWS::EC2::Route", + }, + "VpcPublicSubnet2EIP3C605A87": Object { + "Properties": Object { + "Domain": "vpc", + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet2", + }, + ], + }, + "Type": "AWS::EC2::EIP", + }, + "VpcPublicSubnet2NATGateway9182C01D": Object { + "Properties": Object { + "AllocationId": Object { + "Fn::GetAtt": Array [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId", + ], + }, + "SubnetId": Object { + "Ref": "VpcPublicSubnet2Subnet691E08A3", + }, + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet2", + }, + ], + }, + "Type": "AWS::EC2::NatGateway", + }, + "VpcPublicSubnet2RouteTable94F7E489": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet2", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::RouteTable", + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": Object { + "Properties": Object { + "RouteTableId": Object { + "Ref": "VpcPublicSubnet2RouteTable94F7E489", + }, + "SubnetId": Object { + "Ref": "VpcPublicSubnet2Subnet691E08A3", + }, + }, + "Type": "AWS::EC2::SubnetRouteTableAssociation", + }, + "VpcPublicSubnet2Subnet691E08A3": Object { + "Properties": Object { + "AvailabilityZone": Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::GetAZs": "", + }, + ], + }, + "CidrBlock": "10.0.64.0/18", + "MapPublicIpOnLaunch": true, + "Tags": Array [ + Object { + "Key": "aws-cdk:subnet-name", + "Value": "Public", + }, + Object { + "Key": "aws-cdk:subnet-type", + "Value": "Public", + }, + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet2", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::Subnet", + }, + "VpcVPCGWBF912B6E": Object { + "Properties": Object { + "InternetGatewayId": Object { + "Ref": "VpcIGWD7BA715C", + }, + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::VPCGatewayAttachment", + }, + "kafka5BADF433": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "BrokerNodeGroupInfo": Object { + "ClientSubnets": Array [ + Object { + "Ref": "VpcPrivateSubnet1Subnet536B997A", + }, + Object { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1", + }, + ], + "InstanceType": "kafka.m5.large", + "SecurityGroups": Array [ + "sg-123", + "sg-456", + ], + "StorageInfo": Object { + "EBSStorageInfo": Object { + "VolumeSize": 100, + }, + }, + }, + "ClientAuthentication": Object { + "Tls": Object { + "CertificateAuthorityArnList": Array [ + "arn:aws:acm-pca:us-west-2:1234567890:certificate-authority/11111111-1111-1111-1111-111111111111", + ], + }, + }, + "ClusterName": "test-cluster", + "EncryptionInfo": Object { + "EncryptionAtRest": Object { + "DataVolumeKMSKeyId": "1234abc", + }, + "EncryptionInTransit": Object { + "ClientBroker": "TLS", + "InCluster": true, + }, + }, + "EnhancedMonitoring": "PER_TOPIC_PER_BROKER", + "KafkaVersion": "2.6.1", + "LoggingInfo": Object { + "BrokerLogs": Object { + "CloudWatchLogs": Object { + "Enabled": true, + "LogGroup": "a-log-group", + }, + "Firehose": Object { + "DeliveryStream": "a-delivery-stream", + "Enabled": true, + }, + "S3": Object { + "Bucket": "a-bucket", + "Enabled": true, + }, + }, + }, + "NumberOfBrokerNodes": 2, + "OpenMonitoring": Object { + "Prometheus": Object { + "JmxExporter": Object { + "EnabledInBroker": true, + }, + "NodeExporter": Object { + "EnabledInBroker": true, + }, + }, + }, + }, + "Type": "AWS::MSK::Cluster", + "UpdateReplacePolicy": "Retain", + }, + "sg1fromsg32181E6F4C07E": Object { + "Properties": Object { + "Description": "from sg3:2181", + "FromPort": 2181, + "GroupId": "sg-123", + "IpProtocol": "tcp", + "SourceSecurityGroupId": "sg-3", + "ToPort": 2181, + }, + "Type": "AWS::EC2::SecurityGroupIngress", + }, + "sg2fromsg32181884B3B9E": Object { + "Properties": Object { + "Description": "from sg3:2181", + "FromPort": 2181, + "GroupId": "sg-456", + "IpProtocol": "tcp", + "SourceSecurityGroupId": "sg-3", + "ToPort": 2181, + }, + "Type": "AWS::EC2::SecurityGroupIngress", + }, + }, +} +`; diff --git a/packages/@aws-cdk/aws-msk/test/cluster.test.ts b/packages/@aws-cdk/aws-msk/test/cluster.test.ts new file mode 100644 index 0000000000000..8017deb305e78 --- /dev/null +++ b/packages/@aws-cdk/aws-msk/test/cluster.test.ts @@ -0,0 +1,495 @@ +import { ResourcePart, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; + +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; +import * as logs from '@aws-cdk/aws-logs'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as core from '@aws-cdk/core'; +import * as msk from '../lib'; + +/* eslint-disable quote-props */ +describe('MSK Cluster', () => { + let stack: core.Stack; + let vpc: ec2.IVpc; + + beforeEach(() => { + stack = new core.Stack(); + vpc = new ec2.Vpc(stack, 'Vpc'); + }); + + test('created with default properties', () => { + new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + }); + + expect(stack).toHaveResourceLike( + 'AWS::MSK::Cluster', + { + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }, + ResourcePart.CompleteDefinition, + ); + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + KafkaVersion: '2.6.1', + }); + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + EncryptionInfo: { + EncryptionInTransit: { ClientBroker: 'TLS', InCluster: true }, + }, + }); + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + NumberOfBrokerNodes: 2, + }); + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + BrokerNodeGroupInfo: { + StorageInfo: { EBSStorageInfo: { VolumeSize: 1000 } }, + }, + }); + expect(stack).toHaveResource('AWS::EC2::SecurityGroup'); + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + BrokerNodeGroupInfo: { + SecurityGroups: [ + { + 'Fn::GetAtt': ['ClusterSecurityGroup0921994B', 'GroupId'], + }, + ], + }, + }); + }); + + describe('created with authentication enabled', () => { + describe('with tls auth', () => { + test('fails if client broker encryption is set to plaintext', () => { + + expect(() => new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.PLAINTEXT, + }, + clientAuthentication: msk.ClientAuthentication.tls({ + certificateAuthorityArns: [ + 'arn:aws:acm-pca:us-west-2:1234567890:certificate-authority/11111111-1111-1111-1111-111111111111', + ], + }), + })).toThrow( + 'To enable client authentication, you must enabled TLS-encrypted traffic between clients and brokers.', + ); + }); + }); + + describe('with sasl/scram auth', () => { + test('fails if tls encryption is set to plaintext', () => { + expect(() => new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.PLAINTEXT, + }, + clientAuthentication: msk.ClientAuthentication.sasl({ + scram: true, + }), + }), + ).toThrow( + 'To enable client authentication, you must enabled TLS-encrypted traffic between clients and brokers.', + ); + }); + + test('fails if tls encryption is set to tls and plaintext', () => { + expect(() => new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.TLS_PLAINTEXT, + }, + clientAuthentication: msk.ClientAuthentication.sasl({ + scram: true, + }), + })).toThrow( + 'To enable SASL/SCRAM authentication, you must only allow TLS-encrypted traffic between clients and brokers.', + ); + }); + }); + + describe('creates a customer master key', () => { + beforeEach(() => { + new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.TLS, + }, + clientAuthentication: msk.ClientAuthentication.sasl({ + scram: true, + }), + }); + }); + + test('with alias msk/${clusterName}/sasl/scram', () => { + expect(stack).toHaveResourceLike('AWS::KMS::Alias', { + AliasName: 'alias/msk/cluster/sasl/scram', + }); + }); + + test('with a policy allowing the secrets manager service to use the key', () => { + expect(stack).toHaveResourceLike('AWS::KMS::Key', { + KeyPolicy: { + Statement: [ + { + Action: [ + 'kms:Create*', + 'kms:Describe*', + 'kms:Enable*', + 'kms:List*', + 'kms:Put*', + 'kms:Update*', + 'kms:Revoke*', + 'kms:Disable*', + 'kms:Get*', + 'kms:Delete*', + 'kms:ScheduleKeyDeletion', + 'kms:CancelKeyDeletion', + 'kms:GenerateDataKey', + 'kms:TagResource', + 'kms:UntagResource', + ], + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Resource: '*', + }, + { + Action: [ + 'kms:Encrypt', + 'kms:Decrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + 'kms:CreateGrant', + 'kms:DescribeKey', + ], + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + 'kms:CallerAccount': { + Ref: 'AWS::AccountId', + }, + }, + }, + Effect: 'Allow', + Principal: '*', + Resource: '*', + }, + ], + }, + }); + }); + }); + }); + + describe('created with an instance type set', () => { + test('prefixes instance type with "kafka"', () => { + new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + instanceType: ec2.InstanceType.of( + ec2.InstanceClass.M5, + ec2.InstanceSize.XLARGE, + ), + }); + + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + BrokerNodeGroupInfo: { InstanceType: 'kafka.m5.xlarge' }, + }); + }); + }); + + test('prefixes instance type with "kafka"', () => { + new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + instanceType: ec2.InstanceType.of( + ec2.InstanceClass.M5, + ec2.InstanceSize.XLARGE, + ), + }); + + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + BrokerNodeGroupInfo: { InstanceType: 'kafka.m5.xlarge' }, + }); + }); + + describe('created with logging enabled', () => { + test('log group is set', () => { + new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + logging: { + cloudwatchLogGroup: new logs.LogGroup(stack, 'LogGroup'), + }, + }); + + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + LoggingInfo: { + BrokerLogs: { + CloudWatchLogs: { + Enabled: true, + LogGroup: { + Ref: 'LogGroupF5B46931', + }, + }, + }, + }, + }); + }); + + test('s3 bucket is set', () => { + new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + logging: { + s3: { bucket: new s3.Bucket(stack, 'Bucket') }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + LoggingInfo: { + BrokerLogs: { + S3: { + Bucket: { + Ref: 'Bucket83908E77', + }, + Enabled: true, + }, + }, + }, + }); + }); + + test('firehose delivery stream is set', () => { + new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + logging: { + firehoseDeliveryStreamName: 'a-stream', + }, + }); + + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + LoggingInfo: { + BrokerLogs: { + Firehose: { + DeliveryStream: 'a-stream', + Enabled: true, + }, + }, + }, + }); + }); + }); + + describe('ebs volume size is within bounds', () => { + test('exceeds max', () => { + expect(() => new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + ebsStorageInfo: { volumeSize: 16385 }, + })).toThrow( + 'EBS volume size should be in the range 1-16384', + ); + }); + + test('below minimum', () => { + expect(() => new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + ebsStorageInfo: { volumeSize: 0 }, + })).toThrow( + 'EBS volume size should be in the range 1-16384', + ); + }); + }); + + test('create an encrypted cluster with a custom KMS key', () => { + new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + ebsStorageInfo: { encryptionKey: new kms.Key(stack, 'Key') }, + }); + + expect(stack).toHaveResourceLike('AWS::MSK::Cluster', { + EncryptionInfo: { + EncryptionAtRest: { + DataVolumeKMSKeyId: { + Ref: 'Key961B73FD', + }, + }, + }, + }); + }); + + describe('importing an existing cluster with an ARN', () => { + const clusterArn = + 'arn:aws:kafka:us-west-2:111111111111:cluster/a-cluster/11111111-1111-1111-1111-111111111111-1'; + let cluster: msk.ICluster; + + beforeEach(() => { + cluster = msk.Cluster.fromClusterArn(stack, 'Cluster', clusterArn); + }); + test('cluster name is set', () => { + expect(cluster.clusterName).toEqual('a-cluster'); + }); + + test('cluster arn is set', () => { + expect(cluster.clusterArn).toEqual(clusterArn); + }); + }); + + test('Snapshot test with all values set', () => { + const cluster = new msk.Cluster(stack, 'kafka', { + clusterName: 'test-cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + securityGroups: [ + ec2.SecurityGroup.fromSecurityGroupId(stack, 'sg1', 'sg-123'), + ec2.SecurityGroup.fromSecurityGroupId(stack, 'sg2', 'sg-456'), + ], + ebsStorageInfo: { + volumeSize: 100, + encryptionKey: kms.Key.fromKeyArn( + stack, + 'kms', + 'arn:aws:kms:us-east-1:111122223333:key/1234abc', + ), + }, + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.TLS, + }, + clientAuthentication: msk.ClientAuthentication.tls({ + certificateAuthorityArns: [ + 'arn:aws:acm-pca:us-west-2:1234567890:certificate-authority/11111111-1111-1111-1111-111111111111', + ], + }), + monitoring: { + enablePrometheusJmxExporter: true, + enablePrometheusNodeExporter: true, + clusterMonitoringLevel: msk.ClusterMonitoringLevel.PER_TOPIC_PER_BROKER, + }, + logging: { + s3: { + bucket: s3.Bucket.fromBucketName(stack, 'Bucket', 'a-bucket'), + }, + cloudwatchLogGroup: logs.LogGroup.fromLogGroupName( + stack, + 'LogGroup', + 'a-log-group', + ), + firehoseDeliveryStreamName: 'a-delivery-stream', + }, + }); + + cluster.connections.allowFrom( + ec2.SecurityGroup.fromSecurityGroupId(stack, 'sg3', 'sg-3'), + ec2.Port.tcp(2181), + ); + + // THEN + expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); + }); + + describe('when creating sasl/scram users', () => { + test('fails if sasl/scram not enabled', () => { + const cluster = new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + }); + + expect(() => cluster.addUser('my-user')).toThrow( + 'Cannot create users if an authentication KMS key has not been created/provided.', + ); + }); + + test('creates a secret with the secret name prefixed with AmazonMSK_', () => { + const cluster = new msk.Cluster(stack, 'Cluster', { + clusterName: 'cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + clientAuthentication: msk.ClientAuthentication.sasl({ + scram: true, + }), + }); + + const username = 'my-user'; + cluster.addUser(username); + + expect(stack).toHaveResourceLike('AWS::SecretsManager::Secret', { + 'Name': { + 'Fn::Join': [ + '', + [ + 'AmazonMSK_', + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '/', + { + 'Ref': 'ClusterEB0386A7', + }, + ], + }, + ], + }, + '_my-user', + ], + ], + }, + }); + }); + }); +}); + diff --git a/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json b/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json new file mode 100644 index 0000000000000..43769c1b25ac8 --- /dev/null +++ b/packages/@aws-cdk/aws-msk/test/integ.cluster.expected.json @@ -0,0 +1,610 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-msk-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "ClusterSecurityGroup0921994B": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "MSK security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "ClusterEB0386A7": { + "Type": "AWS::MSK::Cluster", + "Properties": { + "BrokerNodeGroupInfo": { + "ClientSubnets": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ], + "InstanceType": "kafka.m5.large", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ], + "StorageInfo": { + "EBSStorageInfo": { + "VolumeSize": 1000 + } + } + }, + "ClusterName": "integ-test", + "KafkaVersion": "2.6.1", + "NumberOfBrokerNodes": 2, + "EncryptionInfo": { + "EncryptionInTransit": { + "ClientBroker": "TLS", + "InCluster": true + } + }, + "LoggingInfo": { + "BrokerLogs": { + "CloudWatchLogs": { + "Enabled": false + }, + "Firehose": { + "Enabled": false + }, + "S3": { + "Enabled": false + } + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterBootstrapBrokersBootstrapBrokerStringTlsCustomResourcePolicy13FC2126": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "kafka:GetBootstrapBrokers", + "Effect": "Allow", + "Resource": { + "Ref": "ClusterEB0386A7" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ClusterBootstrapBrokersBootstrapBrokerStringTlsCustomResourcePolicy13FC2126", + "Roles": [ + { + "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + } + ] + } + }, + "ClusterBootstrapBrokersBootstrapBrokerStringTls2E6167B7": { + "Type": "Custom::AWS", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "AWS679f53fac002430cb0da5b7982bd22872D164C4C", + "Arn" + ] + }, + "Create": { + "Fn::Join": [ + "", + [ + "{\"service\":\"Kafka\",\"action\":\"getBootstrapBrokers\",\"parameters\":{\"ClusterArn\":\"", + { + "Ref": "ClusterEB0386A7" + }, + "\"},\"physicalResourceId\":{\"id\":\"BootstrapBrokers\"}}" + ] + ] + }, + "Update": { + "Fn::Join": [ + "", + [ + "{\"service\":\"Kafka\",\"action\":\"getBootstrapBrokers\",\"parameters\":{\"ClusterArn\":\"", + { + "Ref": "ClusterEB0386A7" + }, + "\"},\"physicalResourceId\":{\"id\":\"BootstrapBrokers\"}}" + ] + ] + }, + "InstallLatestAwsSdk": true + }, + "DependsOn": [ + "ClusterBootstrapBrokersBootstrapBrokerStringTlsCustomResourcePolicy13FC2126" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "AWS679f53fac002430cb0da5b7982bd22872D164C4C": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7" + }, + "S3Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7" + } + ] + } + ] + } + ] + ] + } + }, + "Role": { + "Fn::GetAtt": [ + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs12.x", + "Timeout": 120 + }, + "DependsOn": [ + "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + ] + } + }, + "Parameters": { + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3Bucket4DD075F7": { + "Type": "String", + "Description": "S3 bucket for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" + }, + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98S3VersionKeyBD0E03B7": { + "Type": "String", + "Description": "S3 key for asset version \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" + }, + "AssetParametersb965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98ArtifactHash35A756EB": { + "Type": "String", + "Description": "Artifact hash for asset \"b965ea3084ec95e24846d4975623e62a02c21883c3ddea9366b2ae42d21cef98\"" + } + }, + "Outputs": { + "BootstrapBrokers": { + "Value": { + "Fn::GetAtt": [ + "ClusterBootstrapBrokersBootstrapBrokerStringTls2E6167B7", + "BootstrapBrokerStringTls" + ] + } + }, + "BootstrapBrokers2": { + "Value": { + "Fn::GetAtt": [ + "ClusterBootstrapBrokersBootstrapBrokerStringTls2E6167B7", + "BootstrapBrokerStringTls" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-msk/test/integ.cluster.ts b/packages/@aws-cdk/aws-msk/test/integ.cluster.ts new file mode 100644 index 0000000000000..c422a26b5cc32 --- /dev/null +++ b/packages/@aws-cdk/aws-msk/test/integ.cluster.ts @@ -0,0 +1,21 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as msk from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-msk-integ'); + +const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2 }); + +const cluster = new msk.Cluster(stack, 'Cluster', { + clusterName: 'integ-test', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); + +// Test lazy instance of the AwsCustomResource +new cdk.CfnOutput(stack, 'BootstrapBrokers', { value: cluster.bootstrapBrokersTls }); +new cdk.CfnOutput(stack, 'BootstrapBrokers2', { value: cluster.bootstrapBrokersTls }); + +app.synth(); diff --git a/packages/@aws-cdk/aws-msk/test/msk.test.ts b/packages/@aws-cdk/aws-msk/test/msk.test.ts deleted file mode 100644 index c4505ad966984..0000000000000 --- a/packages/@aws-cdk/aws-msk/test/msk.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@aws-cdk/assert-internal/jest'; -import {} from '../lib'; - -test('No tests are specified for this package', () => { - expect(true).toBe(true); -}); diff --git a/packages/@aws-cdk/aws-mwaa/package.json b/packages/@aws-cdk/aws-mwaa/package.json index 0f637c25bae91..2dbff02703748 100644 --- a/packages/@aws-cdk/aws-mwaa/package.json +++ b/packages/@aws-cdk/aws-mwaa/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index 6d9dceaf08c91..ecdc6186f0069 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-networkfirewall/package.json b/packages/@aws-cdk/aws-networkfirewall/package.json index 6619dadb53106..389850a3e50c6 100644 --- a/packages/@aws-cdk/aws-networkfirewall/package.json +++ b/packages/@aws-cdk/aws-networkfirewall/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index 519fd0b472337..8532a917c0b58 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-nimblestudio/package.json b/packages/@aws-cdk/aws-nimblestudio/package.json index ae99b67f96f24..ad996a406ab31 100644 --- a/packages/@aws-cdk/aws-nimblestudio/package.json +++ b/packages/@aws-cdk/aws-nimblestudio/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/assert-internal": "0.0.0", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index 70daf8b25c97f..d85cc277ce33c 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 26ea730c62b98..1dc82ec196ef6 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index 8cea6c18b9181..3b40bc91a515c 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index c4bd0b4d0417d..c051cfd621e43 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index 7ed6fb60ee1c4..1857513cb738a 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-quicksight/package.json b/packages/@aws-cdk/aws-quicksight/package.json index 72b7fdfdcfd86..16b54c3f40a2e 100644 --- a/packages/@aws-cdk/aws-quicksight/package.json +++ b/packages/@aws-cdk/aws-quicksight/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index ab258583176da..0a5bdfcc9bc41 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts index f42e27bc7f90b..b1d67f65ce2b8 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance-engine.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance-engine.ts @@ -156,36 +156,81 @@ abstract class InstanceEngineBase implements IInstanceEngine { * (those returned by {@link DatabaseInstanceEngine.mariaDb}). */ export class MariaDbEngineVersion { - /** Version "10.0" (only a major version, without a specific minor version). */ + /** + * Version "10.0" (only a major version, without a specific minor version). + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0 = MariaDbEngineVersion.of('10.0', '10.0'); - /** Version "10.0.17". */ + /** + * Version "10.0.17". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_17 = MariaDbEngineVersion.of('10.0.17', '10.0'); - /** Version "10.0.24". */ + /** + * Version "10.0.24". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_24 = MariaDbEngineVersion.of('10.0.24', '10.0'); - /** Version "10.0.28". */ + /** + * Version "10.0.28". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_28 = MariaDbEngineVersion.of('10.0.28', '10.0'); - /** Version "10.0.31". */ + /** + * Version "10.0.31". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_31 = MariaDbEngineVersion.of('10.0.31', '10.0'); - /** Version "10.0.32". */ + /** + * Version "10.0.32". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_32 = MariaDbEngineVersion.of('10.0.32', '10.0'); - /** Version "10.0.34". */ + /** + * Version "10.0.34". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_34 = MariaDbEngineVersion.of('10.0.34', '10.0'); - /** Version "10.0.35". */ + /** + * Version "10.0.35". + * @deprecated MariaDB 10.0 will reach end of life on May 18, 2021 + */ public static readonly VER_10_0_35 = MariaDbEngineVersion.of('10.0.35', '10.0'); - /** Version "10.1" (only a major version, without a specific minor version). */ + /** + * Version "10.1" (only a major version, without a specific minor version). + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1 = MariaDbEngineVersion.of('10.1', '10.1'); - /** Version "10.1.14". */ + /** + * Version "10.1.14". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_14 = MariaDbEngineVersion.of('10.1.14', '10.1'); - /** Version "10.1.19". */ + /** + * Version "10.1.19". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_19 = MariaDbEngineVersion.of('10.1.19', '10.1'); - /** Version "10.1.23". */ + /** + * Version "10.1.23". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_23 = MariaDbEngineVersion.of('10.1.23', '10.1'); - /** Version "10.1.26". */ + /** + * Version "10.1.26". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_26 = MariaDbEngineVersion.of('10.1.26', '10.1'); - /** Version "10.1.31". */ + /** + * Version "10.1.31". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_31 = MariaDbEngineVersion.of('10.1.31', '10.1'); - /** Version "10.1.34". */ + /** + * Version "10.1.34". + * @deprecated MariaDB 10.1 will reach end of life on May 18, 2021 + */ public static readonly VER_10_1_34 = MariaDbEngineVersion.of('10.1.34', '10.1'); /** Version "10.2" (only a major version, without a specific minor version). */ @@ -198,6 +243,8 @@ export class MariaDbEngineVersion { public static readonly VER_10_2_15 = MariaDbEngineVersion.of('10.2.15', '10.2'); /** Version "10.2.21". */ public static readonly VER_10_2_21 = MariaDbEngineVersion.of('10.2.21', '10.2'); + /** Version "10.2.32". */ + public static readonly VER_10_2_32 = MariaDbEngineVersion.of('10.2.32', '10.2'); /** Version "10.3" (only a major version, without a specific minor version). */ public static readonly VER_10_3 = MariaDbEngineVersion.of('10.3', '10.3'); @@ -282,44 +329,101 @@ class MariaDbInstanceEngine extends InstanceEngineBase { * (those returned by {@link DatabaseInstanceEngine.mysql}). */ export class MysqlEngineVersion { - /** Version "5.5" (only a major version, without a specific minor version). */ + /** + * Version "5.5" (only a major version, without a specific minor version). + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5 = MysqlEngineVersion.of('5.5', '5.5'); - /** Version "5.5.46". */ + /** + * Version "5.5.46". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_46 = MysqlEngineVersion.of('5.5.46', '5.5'); - /** Version "5.5.53". */ + /** + * Version "5.5.53". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_53 = MysqlEngineVersion.of('5.5.53', '5.5'); - /** Version "5.5.57". */ + /** + * Version "5.5.57". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_57 = MysqlEngineVersion.of('5.5.57', '5.5'); - /** Version "5.5.59". */ + /** + * Version "5.5.59". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_59 = MysqlEngineVersion.of('5.5.59', '5.5'); - /** Version "5.5.61". */ + /** + * Version "5.5.61". + * @deprecated MySQL 5.5 will reach end of life on May 25, 2021 + */ public static readonly VER_5_5_61 = MysqlEngineVersion.of('5.5.61', '5.5'); - /** Version "5.6" (only a major version, without a specific minor version). */ + /** + * Version "5.6" (only a major version, without a specific minor version). + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6 = MysqlEngineVersion.of('5.6', '5.6'); - /** Version "5.6.34". */ + /** + * Version "5.6.34". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_34 = MysqlEngineVersion.of('5.6.34', '5.6'); - /** Version "5.6.35". */ + /** + * Version "5.6.35". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_35 = MysqlEngineVersion.of('5.6.35', '5.6'); - /** Version "5.6.37". */ + /** + * Version "5.6.37". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_37 = MysqlEngineVersion.of('5.6.37', '5.6'); - /** Version "5.6.39". */ + /** + * Version "5.6.39". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_39 = MysqlEngineVersion.of('5.6.39', '5.6'); - /** Version "5.6.40". */ + /** + * Version "5.6.40". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_40 = MysqlEngineVersion.of('5.6.40', '5.6'); - /** Version "5.6.41". */ + /** + * Version "5.6.41". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_41 = MysqlEngineVersion.of('5.6.41', '5.6'); - /** Version "5.6.43". */ + /** + * Version "5.6.43". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_43 = MysqlEngineVersion.of('5.6.43', '5.6'); - /** Version "5.6.44". */ + /** + * Version "5.6.44". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_44 = MysqlEngineVersion.of('5.6.44', '5.6'); - /** Version "5.6.46". */ + /** + * Version "5.6.46". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_46 = MysqlEngineVersion.of('5.6.46', '5.6'); - /** Version "5.6.48". */ + /** + * Version "5.6.48". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_48 = MysqlEngineVersion.of('5.6.48', '5.6'); - /** Version "5.6.49". */ + /** + * Version "5.6.49". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_49 = MysqlEngineVersion.of('5.6.49', '5.6'); - /** Version "5.6.51". */ + /** + * Version "5.6.51". + * @deprecated MySQL 5.6 will reach end of life on August 3, 2021 + */ public static readonly VER_5_6_51 = MysqlEngineVersion.of('5.6.51', '5.6'); /** Version "5.7" (only a major version, without a specific minor version). */ @@ -614,6 +718,16 @@ export class PostgresEngineVersion { * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 */ public static readonly VER_9_6_19 = PostgresEngineVersion.of('9.6.19', '9.6'); + /** + * Version "9.6.20". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ + public static readonly VER_9_6_20 = PostgresEngineVersion.of('9.6.20', '9.6'); + /** + * Version "9.6.21". + * @deprecated PostgreSQL 9.6 will reach end of life in November 2021 + */ + public static readonly VER_9_6_21 = PostgresEngineVersion.of('9.6.21', '9.6'); /** Version "10" (only a major version, without a specific minor version). */ public static readonly VER_10 = PostgresEngineVersion.of('10', '10'); @@ -641,6 +755,10 @@ export class PostgresEngineVersion { public static readonly VER_10_13 = PostgresEngineVersion.of('10.13', '10', { s3Import: true }); /** Version "10.14". */ public static readonly VER_10_14 = PostgresEngineVersion.of('10.14', '10', { s3Import: true }); + /** Version "10.15". */ + public static readonly VER_10_15 = PostgresEngineVersion.of('10.15', '10', { s3Import: true }); + /** Version "10.16". */ + public static readonly VER_10_16 = PostgresEngineVersion.of('10.16', '10', { s3Import: true }); /** Version "11" (only a major version, without a specific minor version). */ public static readonly VER_11 = PostgresEngineVersion.of('11', '11', { s3Import: true }); @@ -660,6 +778,10 @@ export class PostgresEngineVersion { public static readonly VER_11_8 = PostgresEngineVersion.of('11.8', '11', { s3Import: true }); /** Version "11.9". */ public static readonly VER_11_9 = PostgresEngineVersion.of('11.9', '11', { s3Import: true }); + /** Version "11.10". */ + public static readonly VER_11_10 = PostgresEngineVersion.of('11.10', '11', { s3Import: true }); + /** Version "11.11". */ + public static readonly VER_11_11 = PostgresEngineVersion.of('11.11', '11', { s3Import: true }); /** Version "12" (only a major version, without a specific minor version). */ public static readonly VER_12 = PostgresEngineVersion.of('12', '12', { s3Import: true }); @@ -671,11 +793,15 @@ export class PostgresEngineVersion { public static readonly VER_12_4 = PostgresEngineVersion.of('12.4', '12', { s3Import: true }); /** Version "12.5". */ public static readonly VER_12_5 = PostgresEngineVersion.of('12.5', '12', { s3Import: true }); + /** Version "12.6". */ + public static readonly VER_12_6 = PostgresEngineVersion.of('12.6', '12', { s3Import: true }); /** Version "13" (only a major version, without a specific minor version). */ public static readonly VER_13 = PostgresEngineVersion.of('13', '13', { s3Import: true }); /** Version "13.1". */ public static readonly VER_13_1 = PostgresEngineVersion.of('13.1', '13', { s3Import: true }); + /** Version "13.2". */ + public static readonly VER_13_2 = PostgresEngineVersion.of('13.2', '13', { s3Import: true }); /** * Create a new PostgresEngineVersion with an arbitrary version. diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index 56d3560bbff45..c11aad528afcd 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/cx-api": "0.0.0", diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index f4e1051f5e544..2be4205d5afe8 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index dd3ed3543dfe9..b93e2693d95cd 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index 9a82371376392..1e3ca117d60e9 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index 3b9bead6d6eab..0dc548943032b 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -63,7 +63,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index 0f36ba8d8a8fc..d7014a4e26151 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -62,7 +62,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index c75c39d0b253c..004a55507b021 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -71,8 +71,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.75", - "@types/jest": "^26.0.22", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", "@types/nodeunit": "^0.0.31", "aws-sdk": "^2.848.0", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index e5f47faa7849f..2f297377c17ab 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index b73a1c7fb6fbc..646ca2feb968f 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -69,7 +69,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 72611eef417e9..37c01e5a1fe72 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -78,7 +78,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/cx-api": "0.0.0", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index 1f254fd4afe87..631f925e9e85e 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -62,7 +62,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index 2ef23af598709..d81c3002b3f7a 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -71,8 +71,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.75", - "@types/jest": "^26.0.22", + "@types/aws-lambda": "^8.10.76", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3objectlambda/package.json b/packages/@aws-cdk/aws-s3objectlambda/package.json index e5a21a6ba4d68..9290f9ae9b2d7 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/package.json +++ b/packages/@aws-cdk/aws-s3objectlambda/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3outposts/package.json b/packages/@aws-cdk/aws-s3outposts/package.json index f15cc407f5841..d7d883fa69912 100644 --- a/packages/@aws-cdk/aws-s3outposts/package.json +++ b/packages/@aws-cdk/aws-s3outposts/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index 50866149deb92..dc213cf4ca8c1 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 1227fa7210375..0cb76210d9b1c 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -72,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.4", + "ts-jest": "^26.5.6", "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index eba2850eeaf5c..4f6e583a82ced 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index d5ee9b774acd5..503450cd297b4 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -72,7 +72,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index 19cc1a192effe..4ccfef27c4f79 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index c4da06ffd570c..ff4a03d2d8458 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json index 96abc46b2ff7e..ada592033fcc8 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json @@ -75,7 +75,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index a83991dd9f2af..1c8644ac79069 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -63,7 +63,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 8125bd4e1595d..6648518b288f4 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -70,7 +70,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.75", + "@types/aws-lambda": "^8.10.76", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index 13815571629a9..6e3510ffad8e0 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index 9ffaea0e6cbbc..6efc6c6992166 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -62,7 +62,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index cf627584e74c1..416454c1ef8cc 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -2,7 +2,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { - CfnDynamicReference, CfnDynamicReferenceService, + CfnDynamicReference, CfnDynamicReferenceService, CfnParameter, Construct as CompatConstruct, ContextProvider, Fn, IResource, Resource, Stack, Token, } from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -79,14 +79,14 @@ export interface ParameterOptions { * A regular expression used to validate the parameter value. For example, for String types with values restricted to * numbers, you can specify the following: ``^\d+$`` * - * @default - no validation is performed + * @default no validation is performed */ readonly allowedPattern?: string; /** * Information about the parameter that you want to add to the system. * - * @default - none + * @default none */ readonly description?: string; @@ -270,7 +270,7 @@ export interface StringParameterAttributes extends CommonStringParameterAttribut /** * The version number of the value you wish to retrieve. * - * @default - The latest version will be retrieved. + * @default The latest version will be retrieved. */ readonly version?: number; @@ -323,8 +323,9 @@ export class StringParameter extends ParameterBase implements IStringParameter { const type = attrs.type || ParameterType.STRING; - const version = attrs.version ? `:${attrs.version}` : ''; - const stringValue = new CfnDynamicReference(CfnDynamicReferenceService.SSM, `${attrs.parameterName}${version}`).toString(); + const stringValue = attrs.version + ? new CfnDynamicReference(CfnDynamicReferenceService.SSM, `${attrs.parameterName}:${attrs.version}`).toString() + : new CfnParameter(scope as CompatConstruct, `${id}.Parameter`, { type: `AWS::SSM::Parameter::Value<${type}>`, default: attrs.parameterName }).valueAsString; class Import extends ParameterBase { public readonly parameterName = attrs.parameterName; diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.expected.json b/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.expected.json index e1734e3122576..1d3d7baba28e0 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.expected.json +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.expected.json @@ -12,6 +12,12 @@ } }, { + "Parameters": { + "MyValueParameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/My/Public/Parameter" + } + }, "Resources": { "Dummy": { "Type": "AWS::SNS::Topic" @@ -19,7 +25,9 @@ }, "Outputs": { "TheValue": { - "Value": "{{resolve:ssm:/My/Public/Parameter}}" + "Value": { + "Ref": "MyValueParameter" + } } } } diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts index 7f9660984055d..215a91090bc5c 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts @@ -1,3 +1,4 @@ +import { expect } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as ssm from '../lib'; @@ -29,7 +30,16 @@ export = { }); // THEN - test.deepEqual(stack.resolve(ref.stringValue), '{{resolve:ssm:/some/key}}'); + expect(stack).toMatch({ + Parameters: { + RefParameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: '/some/key', + }, + }, + }); + + test.deepEqual(stack.resolve(ref.stringValue), { Ref: 'RefParameter' }); test.done(); }, diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts index 7513842e9354c..8ce26dd03a0c5 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts @@ -304,7 +304,15 @@ export = { }); test.deepEqual(stack.resolve(param.parameterName), 'MyParamName'); test.deepEqual(stack.resolve(param.parameterType), 'String'); - test.deepEqual(stack.resolve(param.stringValue), '{{resolve:ssm:MyParamName}}'); + test.deepEqual(stack.resolve(param.stringValue), { Ref: 'MyParamNameParameter' }); + expect(stack).toMatch({ + Parameters: { + MyParamNameParameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: 'MyParamName', + }, + }, + }); test.done(); }, @@ -546,7 +554,41 @@ export = { const value = ssm.StringParameter.valueForStringParameter(stack, 'my-param-name'); // THEN - test.deepEqual(stack.resolve(value), '{{resolve:ssm:my-param-name}}'); + expect(stack).toMatch({ + Parameters: { + SsmParameterValuemyparamnameC96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: 'my-param-name', + }, + }, + }); + test.deepEqual(stack.resolve(value), { Ref: 'SsmParameterValuemyparamnameC96584B6F00A464EAD1953AFF4B05118Parameter' }); + test.done(); + }, + + 'de-dup based on parameter name'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + ssm.StringParameter.valueForStringParameter(stack, 'my-param-name'); + ssm.StringParameter.valueForStringParameter(stack, 'my-param-name'); + ssm.StringParameter.valueForStringParameter(stack, 'my-param-name-2'); + ssm.StringParameter.valueForStringParameter(stack, 'my-param-name'); + + // THEN + expect(stack).toMatch({ + Parameters: { + SsmParameterValuemyparamnameC96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: 'my-param-name', + }, + SsmParameterValuemyparamname2C96584B6F00A464EAD1953AFF4B05118Parameter: { + Type: 'AWS::SSM::Parameter::Value', + Default: 'my-param-name-2', + }, + }, + }); test.done(); }, diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json index 63897ed73376b..53c8ab4499cfe 100644 --- a/packages/@aws-cdk/aws-sso/package.json +++ b/packages/@aws-cdk/aws-sso/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 6bdbc45223a6b..6e2e51ded665a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -69,7 +69,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-glue": "0.0.0", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json index f9c1c240d5959..c67a1adcd7dd7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.expected.json @@ -127,7 +127,9 @@ "Ec2ClusterDefaultAutoScalingGroupLaunchConfig7B2FED3A": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "Ec2ClusterDefaultAutoScalingGroupInstanceProfileDB232471" @@ -841,6 +843,12 @@ ] } }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } + }, "Outputs": { "stateMachineArn": { "Value": { diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json index 71ede5b22edbc..891777171b73c 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.expected.json @@ -127,7 +127,9 @@ "FargateClusterDefaultAutoScalingGroupLaunchConfig57306899": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { - "ImageId": "{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}", + "ImageId": { + "Ref": "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, "InstanceType": "t2.micro", "IamInstanceProfile": { "Ref": "FargateClusterDefaultAutoScalingGroupInstanceProfile2C0FEF3B" @@ -736,5 +738,11 @@ "StateMachineRoleB840431D" ] } + }, + "Parameters": { + "SsmParameterValueawsserviceecsoptimizedamiamazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id" + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index b3124925ed4f8..d1d7d13e0d730 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index 23b71d9296018..a62ec9b002c44 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-timestream/package.json b/packages/@aws-cdk/aws-timestream/package.json index 91a0631ce29a1..6525a28e80fab 100644 --- a/packages/@aws-cdk/aws-timestream/package.json +++ b/packages/@aws-cdk/aws-timestream/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index 0308a0edfd3b8..b3dbfb66b8a0d 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index a2f2fc502fd09..cbeab0a181cce 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index 49a870c1d2694..f2bc0f5a8151c 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index e563372f61f02..4a14b6c046a1a 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -73,7 +73,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index fb8cbbfa22a1c..0faa24f1dbfa7 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -71,7 +71,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index 1016f2d99ff1f..bf1bf7cec32c4 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -50,7 +50,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0" diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/artifact-schema.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/artifact-schema.ts index 51c19bf226a96..c4facf9fd4f19 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/artifact-schema.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/artifact-schema.ts @@ -77,6 +77,13 @@ export interface AwsCloudFormationStackProperties { * @default - Bootstrap stack version number looked up */ readonly bootstrapStackVersionSsmParameter?: string; + + /** + * Whether this stack should be validated by the CLI after synthesis + * + * @default - false + */ + readonly validateOnSynth?: boolean; } /** diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 90dd11be476e7..e7c5db4003ee8 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -58,12 +58,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/mock-fs": "^4.13.0", - "@types/semver": "^7.3.4", + "@types/semver": "^7.3.5", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", - "mock-fs": "^4.13.0", + "mock-fs": "^4.14.0", "pkglint": "0.0.0", "typescript-json-schema": "^0.50.0" }, diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json index 38c7538f38384..77d3117d0aae2 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json @@ -314,6 +314,10 @@ "bootstrapStackVersionSsmParameter": { "description": "SSM parameter where the bootstrap stack version number can be found\n\nOnly used if `requiresBootstrapStackVersion` is set.\n\n- If this value is not set, the bootstrap stack name must be known at\n deployment time so the stack version can be looked up from the stack\n outputs.\n- If this value is set, the bootstrap stack can have any name because\n we won't need to look it up. (Default - Bootstrap stack version number looked up)", "type": "string" + }, + "validateOnSynth": { + "description": "Whether this stack should be validated by the CLI after synthesis (Default - false)", + "type": "boolean" } }, "required": [ diff --git a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json index 1829f904a3c7a..b056ff69e87b5 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json +++ b/packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.version.json @@ -1 +1 @@ -{"version":"10.0.0"} \ No newline at end of file +{"version":"11.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 497069a37ab62..4f0e79827e7a0 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -26,16 +26,16 @@ "diff": "^5.0.0", "fast-deep-equal": "^3.1.3", "string-width": "^4.2.2", - "table": "^6.3.0" + "table": "^6.7.0" }, "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/string-width": "^4.0.1", "cdk-build-tools": "0.0.0", "fast-check": "^2.14.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.6" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index 029e033e2bb74..218742424f03e 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -378,12 +378,12 @@ "constructs": "^3.3.69" }, "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", "pkglint": "0.0.0", - "ts-jest": "^26.5.4", + "ts-jest": "^26.5.6", "@aws-cdk/assert-internal": "0.0.0" }, "bundledDependencies": [ diff --git a/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/json-in-fn-sub.yaml b/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/json-in-fn-sub.yaml new file mode 100644 index 0000000000000..111490f99c9db --- /dev/null +++ b/packages/@aws-cdk/cloudformation-include/test/test-templates/yaml/json-in-fn-sub.yaml @@ -0,0 +1,26 @@ +AWSTemplateFormatVersion: 2010-09-09 +Parameters: + Stage: + Type: String +Resources: + Dashboard: + Type: AWS::CloudWatch::Dashboard + Properties: + DashboardName: !Sub ${Stage}-Dashboard + DashboardBody: !Sub | + { + "widgets": [ + { + "type": "text", + "properties": { + "markdown": "${Stage} ${Stage}" + } + }, + { + "type": "text", + "properties": { + "markdown": "${Stage} ${Stage}" + } + } + ] + } diff --git a/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts b/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts index 65251fb20775f..06beafcdeb62c 100644 --- a/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts +++ b/packages/@aws-cdk/cloudformation-include/test/yaml-templates.test.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import '@aws-cdk/assert-internal/jest'; +import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import * as core from '@aws-cdk/core'; import * as constructs from 'constructs'; import * as inc from '../lib'; @@ -397,7 +398,7 @@ describe('CDK Include', () => { ); }); - test('can ingest a YAML tempalte with Fn::Sub in string form and output it unchanged', () => { + test('can ingest a YAML template with Fn::Sub in string form and output it unchanged', () => { includeTestTemplate(stack, 'short-form-fnsub-string.yaml'); expect(stack).toMatchTemplate( @@ -405,7 +406,7 @@ describe('CDK Include', () => { ); }); - test('can ingest a YAML tmeplate with Fn::Sub in map form and output it unchanged', () => { + test('can ingest a YAML template with Fn::Sub in map form and output it unchanged', () => { includeTestTemplate(stack, 'short-form-sub-map.yaml'); expect(stack).toMatchTemplate( @@ -413,16 +414,43 @@ describe('CDK Include', () => { ); }); - test('the parser throws an error on a YAML tmeplate with short form import value that uses short form sub', () => { + test('can correctly substitute values inside a string containing JSON passed to Fn::Sub', () => { + const cfnInclude = includeTestTemplate(stack, 'json-in-fn-sub.yaml', { + Stage: 'test', + }); + + const dashboard = cfnInclude.getResource('Dashboard') as cloudwatch.CfnDashboard; + // we need to resolve the Fn::Sub expression to get to its argument + const resolvedDashboardBody = stack.resolve(dashboard.dashboardBody)['Fn::Sub']; + expect(JSON.parse(resolvedDashboardBody)).toStrictEqual({ + "widgets": [ + { + "type": "text", + "properties": { + "markdown": "test test", + }, + }, + { + "type": "text", + "properties": { + "markdown": "test test", + }, + }, + ], + }); + }); + + test('the parser throws an error on a YAML template with short form import value that uses short form sub', () => { expect(() => { includeTestTemplate(stack, 'invalid/short-form-import-sub.yaml'); }).toThrow(/A node can have at most one tag/); }); }); -function includeTestTemplate(scope: constructs.Construct, testTemplate: string): inc.CfnInclude { +function includeTestTemplate(scope: constructs.Construct, testTemplate: string, parameters?: { [key: string]: string }): inc.CfnInclude { return new inc.CfnInclude(scope, 'MyScope', { templateFile: _testTemplateFilePath(testTemplate), + parameters, }); } diff --git a/packages/@aws-cdk/core/lib/cfn-parse.ts b/packages/@aws-cdk/core/lib/cfn-parse.ts index be8f3560210d9..e57bf28e785f3 100644 --- a/packages/@aws-cdk/core/lib/cfn-parse.ts +++ b/packages/@aws-cdk/core/lib/cfn-parse.ts @@ -687,17 +687,23 @@ export class CfnParser { function go(value: string): string { const leftBrace = value.indexOf('${'); - const rightBrace = value.indexOf('}') + 1; - // don't include left and right braces when searching for the target of the reference - if (leftBrace === -1 || leftBrace >= rightBrace) { + if (leftBrace === -1) { + return value; + } + // search for the closing brace to the right of the opening '${' + // (in theory, there could be other braces in the string, + // for example if it represents a JSON object) + const rightBrace = value.indexOf('}', leftBrace); + if (rightBrace === -1) { return value; } const leftHalf = value.substring(0, leftBrace); - const rightHalf = value.substring(rightBrace); - const refTarget = value.substring(leftBrace + 2, rightBrace - 1).trim(); + const rightHalf = value.substring(rightBrace + 1); + // don't include left and right braces when searching for the target of the reference + const refTarget = value.substring(leftBrace + 2, rightBrace).trim(); if (refTarget[0] === '!') { - return value.substring(0, rightBrace) + go(rightHalf); + return value.substring(0, rightBrace + 1) + go(rightHalf); } // lookup in map diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts index d468ce234c4f3..cc5921fb73465 100644 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ b/packages/@aws-cdk/core/lib/construct-compat.ts @@ -43,6 +43,13 @@ export interface ISynthesisSession { * Cloud assembly builder. */ assembly: cxapi.CloudAssemblyBuilder; + + /** + * Whether the stack should be validated after synthesis to check for error metadata + * + * @default - false + */ + validateOnSynth?: boolean; } /** @@ -203,6 +210,13 @@ export interface SynthesisOptions extends cxapi.AssemblyBuildOptions { * @default false */ readonly skipValidation?: boolean; + + /** + * Whether the stack should be validated after synthesis to check for error metadata + * + * @default - false + */ + readonly validateOnSynthesis?: boolean; } /** diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index c8a54267823a8..e865481a59074 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -36,7 +36,7 @@ export function synthesize(root: IConstruct, options: SynthesisOptions = { }): c // next, we invoke "onSynthesize" on all of our children. this will allow // stacks to add themselves to the synthesized cloud assembly. - synthesizeTree(root, builder); + synthesizeTree(root, builder, options.validateOnSynthesis); return builder.buildAssembly(); } @@ -146,11 +146,12 @@ function injectMetadataResources(root: IConstruct) { * * Stop at Assembly boundaries. */ -function synthesizeTree(root: IConstruct, builder: cxapi.CloudAssemblyBuilder) { +function synthesizeTree(root: IConstruct, builder: cxapi.CloudAssemblyBuilder, validateOnSynth: boolean = false) { visit(root, 'post', construct => { const session = { outdir: builder.outdir, assembly: builder, + validateOnSynth, }; if (Stack.isStack(construct)) { diff --git a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts index c5d88c9e76686..211413df2b5ed 100644 --- a/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts +++ b/packages/@aws-cdk/core/lib/stack-synthesizers/_shared.ts @@ -46,6 +46,7 @@ export function addStackArtifactToAssembly( templateFile: stack.templateFile, terminationProtection: stack.terminationProtection, tags: nonEmptyDict(stack.tags.tagValues()), + validateOnSynth: session.validateOnSynth, ...stackProps, ...stackNameProperty, }; diff --git a/packages/@aws-cdk/core/lib/stage.ts b/packages/@aws-cdk/core/lib/stage.ts index ba0fc21d4248d..efe65f115ab55 100644 --- a/packages/@aws-cdk/core/lib/stage.ts +++ b/packages/@aws-cdk/core/lib/stage.ts @@ -179,6 +179,7 @@ export class Stage extends CoreConstruct { if (!this.assembly || options.force) { this.assembly = synthesize(this, { skipValidation: options.skipValidation, + validateOnSynthesis: options.validateOnSynthesis, }); } @@ -210,6 +211,13 @@ export interface StageSynthesisOptions { */ readonly skipValidation?: boolean; + /** + * Whether the stack should be validated after synthesis to check for error metadata + * + * @default - false + */ + readonly validateOnSynthesis?: boolean; + /** * Force a re-synth, even if the stage has already been synthesized. * This is used by tests to allow for incremental verification of the output. diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 40717d8893b6c..af2e803a1f7f8 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -174,12 +174,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.62", + "@types/aws-lambda": "^8.10.76", "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.14", + "@types/jest": "^26.0.23", "@types/lodash": "^4.14.168", "@types/minimatch": "^3.0.4", - "@types/node": "^10.17.56", + "@types/node": "^10.17.59", "@types/sinon": "^9.0.11", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", @@ -188,7 +188,7 @@ "nodeunit-shim": "0.0.0", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-mock-imports": "^1.3.3" + "ts-mock-imports": "^1.3.4" }, "dependencies": { "@aws-cdk/cloud-assembly-schema": "0.0.0", diff --git a/packages/@aws-cdk/core/test/synthesis.test.ts b/packages/@aws-cdk/core/test/synthesis.test.ts index 77c8c306ef81f..710620eceaa3d 100644 --- a/packages/@aws-cdk/core/test/synthesis.test.ts +++ b/packages/@aws-cdk/core/test/synthesis.test.ts @@ -104,7 +104,10 @@ nodeunitShim({ 'one-stack': { type: 'aws:cloudformation:stack', environment: 'aws://unknown-account/unknown-region', - properties: { templateFile: 'one-stack.template.json' }, + properties: { + templateFile: 'one-stack.template.json', + validateOnSynth: false, + }, displayName: 'one-stack', }, }, diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 70ae0de9858e6..c93d01bc53e7e 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -71,11 +71,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "@types/aws-lambda": "^8.10.75", + "@types/aws-lambda": "^8.10.76", "@types/fs-extra": "^8.1.1", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", diff --git a/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts b/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts index 56093d702d2e0..dba5bacb6beb0 100644 --- a/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts +++ b/packages/@aws-cdk/cx-api/lib/artifacts/cloudformation-artifact.ts @@ -94,6 +94,13 @@ export class CloudFormationStackArtifact extends CloudArtifact { */ public readonly terminationProtection?: boolean; + /** + * Whether this stack should be validated by the CLI after synthesis + * + * @default - false + */ + public readonly validateOnSynth?: boolean; + private _template: any | undefined; constructor(assembly: CloudAssembly, artifactId: string, artifact: cxschema.ArtifactManifest) { @@ -119,6 +126,7 @@ export class CloudFormationStackArtifact extends CloudArtifact { this.requiresBootstrapStackVersion = properties.requiresBootstrapStackVersion; this.bootstrapStackVersionSsmParameter = properties.bootstrapStackVersionSsmParameter; this.terminationProtection = properties.terminationProtection; + this.validateOnSynth = properties.validateOnSynth; this.stackName = properties.stackName || artifactId; this.assets = this.findMetadataByType(cxschema.ArtifactMetadataEntryType.ASSET).map(e => e.data as cxschema.AssetMetadataEntry); diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 56804a3a1dc38..e362a20ae0650 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -64,12 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/mock-fs": "^4.13.0", - "@types/semver": "^7.3.4", + "@types/semver": "^7.3.5", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", - "mock-fs": "^4.13.0", + "mock-fs": "^4.14.0", "pkglint": "0.0.0" }, "repository": { diff --git a/packages/@aws-cdk/example-construct-library/package.json b/packages/@aws-cdk/example-construct-library/package.json index 00e9a2ebeca37..0f05299af14d6 100644 --- a/packages/@aws-cdk/example-construct-library/package.json +++ b/packages/@aws-cdk/example-construct-library/package.json @@ -64,7 +64,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/lambda-layer-awscli/package.json b/packages/@aws-cdk/lambda-layer-awscli/package.json index 66cb32781982d..4474e0c74a1bb 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/package.json +++ b/packages/@aws-cdk/lambda-layer-awscli/package.json @@ -64,7 +64,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/lambda-layer-kubectl/package.json b/packages/@aws-cdk/lambda-layer-kubectl/package.json index 9ef9c0540d059..d3d03e9569dfd 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/package.json +++ b/packages/@aws-cdk/lambda-layer-kubectl/package.json @@ -64,7 +64,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@aws-cdk/pipelines/lib/stage.ts b/packages/@aws-cdk/pipelines/lib/stage.ts index 863aa8869d8bd..0fca3f895b584 100644 --- a/packages/@aws-cdk/pipelines/lib/stage.ts +++ b/packages/@aws-cdk/pipelines/lib/stage.ts @@ -75,7 +75,7 @@ export class CdkStage extends CoreConstruct { * publishing stage. */ public addApplication(appStage: Stage, options: AddStageOptions = {}) { - const asm = appStage.synth(); + const asm = appStage.synth({ validateOnSynthesis: true }); const extraRunOrderSpace = options.extraRunOrderSpace ?? 0; if (asm.stacks.length === 0) { diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index 95f1900f2872f..5f9824d49d92f 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -30,7 +30,7 @@ "organization": true }, "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index 85ea061ce952a..47daf4d1d60fa 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -55,7 +55,7 @@ "license": "Apache-2.0", "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.14", + "@types/jest": "^26.0.23", "cdk-build-tools": "0.0.0", "fs-extra": "^9.1.0", "pkglint": "0.0.0" diff --git a/packages/@aws-cdk/yaml-cfn/package.json b/packages/@aws-cdk/yaml-cfn/package.json index c76fe4d4dc2d1..4bb5660823884 100644 --- a/packages/@aws-cdk/yaml-cfn/package.json +++ b/packages/@aws-cdk/yaml-cfn/package.json @@ -67,7 +67,7 @@ "yaml": "1.10.2" }, "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/yaml": "^1.9.7", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index 63b00e82c8e6b..6dab583bf473a 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -34,14 +34,14 @@ "license": "Apache-2.0", "devDependencies": { "@monocdk-experiment/rewrite-imports": "0.0.0", - "@types/jest": "^26.0.22", - "@types/node": "^10.17.56", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", "constructs": "^3.3.69", "jest": "^26.6.3", "monocdk": "0.0.0", "pkglint": "0.0.0", - "ts-jest": "^26.5.4" + "ts-jest": "^26.5.6" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0" diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 17db78f91896d..fcfbe320c9d96 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -32,13 +32,13 @@ }, "license": "Apache-2.0", "dependencies": { - "glob": "^7.1.6", + "glob": "^7.1.7", "typescript": "~3.9.9" }, "devDependencies": { "@types/glob": "^7.1.3", - "@types/jest": "^26.0.22", - "@types/node": "^10.17.56", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", "pkglint": "0.0.0" }, diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 0193f29c38b56..ecc5f73614f4b 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -226,6 +226,7 @@ "@aws-cdk/aws-lambda-destinations": "0.0.0", "@aws-cdk/aws-lambda-event-sources": "0.0.0", "@aws-cdk/aws-lambda-nodejs": "0.0.0", + "@aws-cdk/aws-lambda-go": "0.0.0", "@aws-cdk/aws-lambda-python": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", @@ -301,7 +302,7 @@ "@aws-cdk/pipelines": "0.0.0", "@aws-cdk/region-info": "0.0.0", "@types/fs-extra": "^8.1.1", - "@types/node": "^10.17.56", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", "constructs": "^3.3.69", "fs-extra": "^9.1.0", diff --git a/packages/aws-cdk-migration/package.json b/packages/aws-cdk-migration/package.json index 26b5c61d98bd7..98ecfa881e256 100644 --- a/packages/aws-cdk-migration/package.json +++ b/packages/aws-cdk-migration/package.json @@ -32,13 +32,13 @@ }, "license": "Apache-2.0", "dependencies": { - "glob": "^7.1.6", + "glob": "^7.1.7", "typescript": "~3.9.9" }, "devDependencies": { "@types/glob": "^7.1.3", - "@types/jest": "^26.0.22", - "@types/node": "^10.17.56", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", "pkglint": "0.0.0" }, diff --git a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts index 6c62bdbd7599b..26da10c13e6e2 100644 --- a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts +++ b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts @@ -79,7 +79,8 @@ export class CloudAssembly { selectors = selectors.filter(s => s != null); // filter null/undefined selectors = [...new Set(selectors)]; // make them unique - const stacks = this.assembly.stacksRecursively; + const asm = this.assembly; + const stacks = semver.major(asm.version) < 10 ? asm.stacks : asm.stacksRecursively; if (stacks.length === 0) { throw new Error('This app contains no stacks'); } @@ -189,6 +190,14 @@ export class StackCollection { return new StackCollection(this.assembly, arts); } + public filter(predicate: (art: cxapi.CloudFormationStackArtifact) => boolean): StackCollection { + return new StackCollection(this.assembly, this.stackArtifacts.filter(predicate)); + } + + public concat(other: StackCollection): StackCollection { + return new StackCollection(this.assembly, this.stackArtifacts.concat(other.stackArtifacts)); + } + /** * Extracts 'aws:cdk:warning|info|error' metadata entries from the stack synthesis */ diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 5735ddf28332c..df811e39587be 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -461,12 +461,6 @@ async function canSkipDeploy( return false; } - // Stack retrieves latest version of SSM parameters with dynamic reference - if (/{{resolve:ssm:[a-zA-Z0-9_.-/]+}}/.test(JSON.stringify(deployStackOptions.stack.template))) { - debug(`${deployName}: stack retrieves latest version of SSM parameters with dynamic reference`); - return false; - } - // We can skip deploy return true; } @@ -522,4 +516,4 @@ function restUrlFromManifest(url: string, environment: cxapi.Environment): strin const urlSuffix: string = regionUtil.getEndpointSuffix(environment.region); return `https://s3.${environment.region}.${urlSuffix}/${bucketName}/${objectKey}`; -} +} \ No newline at end of file diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index d7011d743ffaf..9a9a9a1c3a784 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -395,14 +395,17 @@ export class CdkToolkit { private async selectStacksForDiff(stackNames: string[], exclusively?: boolean) { const assembly = await this.assembly(); - const idsToValidate = process.env.STACKS_TO_VALIDATE ? process.env.STACKS_TO_VALIDATE.split(';') : stackNames; - const stacksToValidate = await this.selectStacksForList(idsToValidate); - await this.validateStacks(stacksToValidate); - - return assembly.selectStacks(stackNames, { + const selectedForDiff = await assembly.selectStacks(stackNames, { extend: exclusively ? ExtendedStackSelection.None : ExtendedStackSelection.Upstream, defaultBehavior: DefaultSelection.MainAssembly, }); + + const allStacks = await this.selectStacksForList([]); + const flaggedStacks = allStacks.filter(art => art.validateOnSynth ?? false); + + await this.validateStacks(selectedForDiff.concat(flaggedStacks)); + + return selectedForDiff; } private async selectStacksForDestroy(stackNames: string[], exclusively?: boolean) { diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 8d0983647ff43..b93eb05b444ec 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -39,16 +39,16 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/core": "0.0.0", - "@octokit/rest": "^18.5.2", + "@octokit/rest": "^18.5.3", "@types/archiver": "^5.1.0", "@types/fs-extra": "^8.1.1", "@types/glob": "^7.1.3", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/minimatch": "^3.0.4", "@types/mockery": "^1.4.29", - "@types/node": "^10.17.56", + "@types/node": "^10.17.59", "@types/promptly": "^3.0.1", - "@types/semver": "^7.3.4", + "@types/semver": "^7.3.5", "@types/sinon": "^9.0.11", "@types/table": "^6.0.0", "@types/uuid": "^8.3.0", @@ -62,8 +62,8 @@ "nock": "^13.0.11", "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^26.5.4", - "ts-mock-imports": "^1.3.3", + "ts-jest": "^26.5.6", + "ts-mock-imports": "^1.3.4", "xml-js": "^1.6.11" }, "dependencies": { @@ -78,14 +78,14 @@ "colors": "^1.4.0", "decamelize": "^5.0.0", "fs-extra": "^9.1.0", - "glob": "^7.1.6", + "glob": "^7.1.7", "json-diff": "^0.5.4", "minimatch": ">=3.0", "promptly": "^3.2.0", "proxy-agent": "^4.0.1", "semver": "^7.3.5", "source-map-support": "^0.5.19", - "table": "^6.1.0", + "table": "^6.7.0", "uuid": "^8.3.2", "wrap-ansi": "^7.0.0", "yaml": "1.10.2", diff --git a/packages/aws-cdk/test/api/deploy-stack.test.ts b/packages/aws-cdk/test/api/deploy-stack.test.ts index 31645e6c18d4a..7e4c5484e2f5a 100644 --- a/packages/aws-cdk/test/api/deploy-stack.test.ts +++ b/packages/aws-cdk/test/api/deploy-stack.test.ts @@ -23,17 +23,6 @@ const FAKE_STACK_TERMINATION_PROTECTION = testStack({ terminationProtection: true, }); -const FAKE_STACK_SSM = testStack({ - stackName: 'ssm', - template: { - Outputs: { - MyOutput: { - Value: '{{resolve:ssm:/my/ssm/param}}', - }, - }, - }, -}); - let sdk: MockSdk; let sdkProvider: MockSdkProvider; let cfnMocks: MockedObject>; @@ -646,21 +635,6 @@ test('updateTerminationProtection called when termination protection is undefine })); }); -test('deploy not skipped if template retrieves latest version of SSM parameters', async () => { - // GIVEN - givenStackExists(); - givenTemplateIs(FAKE_STACK_SSM.template); - - // WHEN - await deployStack({ - ...standardDeployStackArguments(), - stack: FAKE_STACK_SSM, - }); - - // THEN - expect(cfnMocks.executeChangeSet).toHaveBeenCalled(); -}); - /** * Set up the mocks so that it looks like the stack exists to start with * @@ -696,4 +670,4 @@ function givenTemplateIs(template: any) { cfnMocks.getTemplate!.mockReturnValue({ TemplateBody: JSON.stringify(template), }); -} +} \ No newline at end of file diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index 5b918889e55a8..61ac68c52baad 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -178,20 +178,58 @@ describe('synth', () => { process.env.STACKS_TO_VALIDATE = undefined; }); - test('with STACKS_TO_VALIDATE containing a failed stack', async() => { - process.env.STACKS_TO_VALIDATE = 'Test-Stack-A;Test-Stack-A/witherrors'; + test('stack has error and is flagged for validation', async() => { + cloudExecutable = new MockCloudExecutable({ + stacks: [ + MockStack.MOCK_STACK_A, + MockStack.MOCK_STACK_B, + ], + nestedAssemblies: [{ + stacks: [ + { properties: { validateOnSynth: true }, ...MockStack.MOCK_STACK_WITH_ERROR }, + ], + }], + }); const toolkit = defaultToolkitSetup(); - await expect(toolkit.synth(['Test-Stack-A'], false, true)).rejects.toBeDefined(); + await expect(toolkit.synth([], false, true)).rejects.toBeDefined(); }); - test('with STACKS_TO_VALIDATE not containing a failed stack', async() => { - process.env.STACKS_TO_VALIDATE = 'Test-Stack-A'; + test('stack has error and was explicitly selected', async() => { + cloudExecutable = new MockCloudExecutable({ + stacks: [ + MockStack.MOCK_STACK_A, + MockStack.MOCK_STACK_B, + ], + nestedAssemblies: [{ + stacks: [ + { properties: { validateOnSynth: false }, ...MockStack.MOCK_STACK_WITH_ERROR }, + ], + }], + }); + + const toolkit = defaultToolkitSetup(); + + await expect(toolkit.synth(['witherrors'], false, true)).rejects.toBeDefined(); + }); + + test('stack has error, is not flagged for validation and was not explicitly selected', async () => { + cloudExecutable = new MockCloudExecutable({ + stacks: [ + MockStack.MOCK_STACK_A, + MockStack.MOCK_STACK_B, + ], + nestedAssemblies: [{ + stacks: [ + { properties: { validateOnSynth: false }, ...MockStack.MOCK_STACK_WITH_ERROR }, + ], + }], + }); const toolkit = defaultToolkitSetup(); - await toolkit.synth(['Test-Stack-A'], false, true); + await toolkit.synth([], false, true); }); }); diff --git a/packages/awslint/package.json b/packages/awslint/package.json index aa25d4f71a420..dab312dc46ea0 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -16,27 +16,27 @@ "awslint": "bin/awslint" }, "dependencies": { - "@jsii/spec": "^1.28.0", + "@jsii/spec": "^1.29.0", "camelcase": "^6.2.0", "colors": "^1.4.0", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.28.0", + "jsii-reflect": "^1.29.0", "yargs": "^16.2.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/yargs": "^15.0.13", "pkglint": "0.0.0", "typescript": "~3.9.9", - "@typescript-eslint/eslint-plugin": "^4.21.0", - "@typescript-eslint/parser": "^4.21.0", - "eslint": "^7.23.0", + "@typescript-eslint/eslint-plugin": "^4.22.1", + "@typescript-eslint/parser": "^4.22.1", + "eslint": "^7.26.0", "eslint-import-resolver-node": "^0.3.4", "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.3.4", + "eslint-plugin-jest": "^24.3.6", "jest": "^26.6.3" }, "repository": { diff --git a/packages/cdk-assets/.gitignore b/packages/cdk-assets/.gitignore index 036ec00533484..d24092a6feda2 100644 --- a/packages/cdk-assets/.gitignore +++ b/packages/cdk-assets/.gitignore @@ -23,3 +23,6 @@ npm-shrinkwrap.json !jest.config.js junit.xml + +# Ignore this symlink, we recreate it at test time +test/test-archive-follow/data/linked diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 48f6d8fba4152..aa751f80283d7 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -32,15 +32,15 @@ "devDependencies": { "@types/archiver": "^5.1.0", "@types/glob": "^7.1.3", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/jszip": "^3.4.1", "@types/mock-fs": "^4.13.0", - "@types/node": "^10.17.56", + "@types/node": "^10.17.59", "@types/yargs": "^15.0.13", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", "jszip": "^3.6.0", - "mock-fs": "^4.13.0", + "mock-fs": "^4.14.0", "pkglint": "0.0.0" }, "dependencies": { @@ -48,7 +48,7 @@ "@aws-cdk/cx-api": "0.0.0", "archiver": "^5.3.0", "aws-sdk": "^2.848.0", - "glob": "^7.1.6", + "glob": "^7.1.7", "yargs": "^16.2.0" }, "repository": { diff --git a/packages/cdk-assets/test/archive.test.ts b/packages/cdk-assets/test/archive.test.ts index afa8b87175b42..92245dc653494 100644 --- a/packages/cdk-assets/test/archive.test.ts +++ b/packages/cdk-assets/test/archive.test.ts @@ -1,6 +1,6 @@ import { exec as _exec } from 'child_process'; import * as crypto from 'crypto'; -import { constants, promises as fs } from 'fs'; +import { constants, exists, promises as fs } from 'fs'; import * as os from 'os'; import * as path from 'path'; import { promisify } from 'util'; @@ -8,6 +8,7 @@ import * as jszip from 'jszip'; import { zipDirectory } from '../lib/private/archive'; import { rmRfSync } from '../lib/private/fs-extra'; const exec = promisify(_exec); +const pathExists = promisify(exists); test('zipDirectory can take a directory and produce a zip from it', async () => { const stagingDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test.archive')); @@ -59,6 +60,18 @@ test('zipDirectory follows symlinks', async () => { const stagingDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test.archive')); const extractDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test.archive.follow')); try { + // First MAKE the symlink we're going to follow. We can't check it into git, because + // CodeBuild/CodePipeline (I forget which) is going to replace symlinks with a textual + // representation of its target upon checkout, for security reasons. So, to make sure + // the symlink exists, we need to create it at build time. + const symlinkPath = path.join(__dirname, 'test-archive-follow', 'data', 'linked'); + const symlinkTarget = '../linked'; + + if (await pathExists(symlinkPath)) { + await fs.unlink(symlinkPath); + } + await fs.symlink(symlinkTarget, symlinkPath, 'dir'); + const originalDir = path.join(__dirname, 'test-archive-follow', 'data'); const zipFile = path.join(stagingDir, 'output.zip'); diff --git a/packages/cdk-assets/test/test-archive-follow/data/linked b/packages/cdk-assets/test/test-archive-follow/data/linked deleted file mode 120000 index c9365cd25131c..0000000000000 --- a/packages/cdk-assets/test/test-archive-follow/data/linked +++ /dev/null @@ -1 +0,0 @@ -../linked \ No newline at end of file diff --git a/packages/cdk-dasm/package.json b/packages/cdk-dasm/package.json index afad698cbe0cf..eb248837815bc 100644 --- a/packages/cdk-dasm/package.json +++ b/packages/cdk-dasm/package.json @@ -26,11 +26,11 @@ }, "license": "Apache-2.0", "dependencies": { - "codemaker": "^1.28.0", + "codemaker": "^1.29.0", "yaml": "1.10.2" }, "devDependencies": { - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/yaml": "1.9.7", "jest": "^26.6.3", "typescript": "~3.9.9" diff --git a/packages/decdk/package.json b/packages/decdk/package.json index c82829e0c1d57..210bc6ee109db 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -145,6 +145,7 @@ "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-lambda-python": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", + "@aws-cdk/aws-lambda-go": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-logs-destinations": "0.0.0", "@aws-cdk/aws-lookoutmetrics": "0.0.0", @@ -219,18 +220,18 @@ "@aws-cdk/region-info": "0.0.0", "constructs": "^3.3.69", "fs-extra": "^9.1.0", - "jsii-reflect": "^1.28.0", + "jsii-reflect": "^1.29.0", "jsonschema": "^1.4.0", "yaml": "1.10.2", "yargs": "^16.2.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/yaml": "1.9.7", "@types/yargs": "^15.0.13", "jest": "^26.6.3", - "jsii": "^1.28.0" + "jsii": "^1.29.0" }, "keywords": [ "aws", diff --git a/packages/monocdk/package.json b/packages/monocdk/package.json index d4a02d85b3350..0a5750d59db78 100644 --- a/packages/monocdk/package.json +++ b/packages/monocdk/package.json @@ -227,6 +227,7 @@ "@aws-cdk/aws-lambda-destinations": "0.0.0", "@aws-cdk/aws-lambda-event-sources": "0.0.0", "@aws-cdk/aws-lambda-nodejs": "0.0.0", + "@aws-cdk/aws-lambda-go": "0.0.0", "@aws-cdk/aws-lambda-python": "0.0.0", "@aws-cdk/aws-licensemanager": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", @@ -303,7 +304,7 @@ "@aws-cdk/region-info": "0.0.0", "@aws-cdk/yaml-cfn": "0.0.0", "@types/fs-extra": "^8.1.1", - "@types/node": "^10.17.56", + "@types/node": "^10.17.59", "cdk-build-tools": "0.0.0", "constructs": "^3.3.69", "fs-extra": "^9.1.0", diff --git a/tools/cdk-build-tools/config/eslintrc.js b/tools/cdk-build-tools/config/eslintrc.js index 8fda93acca482..dd70c99416cd3 100644 --- a/tools/cdk-build-tools/config/eslintrc.js +++ b/tools/cdk-build-tools/config/eslintrc.js @@ -205,5 +205,6 @@ module.exports = { "jest/no-standalone-expect": "off", // nodeunitShim confuses this check. "jest/valid-expect": "off", // expect from '@aws-cdk/assert' can take a second argument "jest/valid-title": "off", // A little over-zealous with test('test foo') being an error. + "jest/no-identical-title": "off", // TEMPORARY - Disabling this until https://github.com/jest-community/eslint-plugin-jest/issues/836 is resolved }, }; diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 346866d6c1189..994b0248e9882 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -34,33 +34,33 @@ "license": "Apache-2.0", "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/yargs": "^15.0.13", - "@types/semver": "^7.3.4", + "@types/semver": "^7.3.5", "pkglint": "0.0.0" }, "dependencies": { - "@typescript-eslint/eslint-plugin": "^4.22.0", - "@typescript-eslint/parser": "^4.22.0", + "@typescript-eslint/eslint-plugin": "^4.22.1", + "@typescript-eslint/parser": "^4.22.1", "awslint": "0.0.0", "colors": "^1.4.0", - "eslint": "^7.24.0", + "eslint": "^7.26.0", "eslint-import-resolver-node": "^0.3.4", "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.3.5", + "eslint-plugin-jest": "^24.3.6", "fs-extra": "^9.1.0", "jest": "^26.6.3", "jest-junit": "^11.1.0", - "jsii": "^1.28.0", - "jsii-pacmak": "^1.28.0", - "jsii-reflect": "^1.28.0", + "jsii": "^1.29.0", + "jsii-pacmak": "^1.29.0", + "jsii-reflect": "^1.29.0", "markdownlint-cli": "^0.27.1", "nodeunit": "^0.11.3", "nyc": "^15.1.0", "semver": "^7.3.5", - "ts-jest": "^26.5.4", + "ts-jest": "^26.5.6", "typescript": "~3.9.9", "yargs": "^16.2.0", "yarn-cling": "0.0.0" diff --git a/tools/cfn2ts/package.json b/tools/cfn2ts/package.json index 82e397b74ce62..b487b3f04c021 100644 --- a/tools/cfn2ts/package.json +++ b/tools/cfn2ts/package.json @@ -30,14 +30,14 @@ "license": "Apache-2.0", "dependencies": { "@aws-cdk/cfnspec": "0.0.0", - "codemaker": "^1.28.0", + "codemaker": "^1.29.0", "fast-json-patch": "^3.0.0-1", "fs-extra": "^9.1.0", "yargs": "^16.2.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.22", + "@types/jest": "^26.0.23", "@types/yargs": "^15.0.13", "cdk-build-tools": "0.0.0", "jest": "^26.6.3", diff --git a/tools/eslint-plugin-cdk/package.json b/tools/eslint-plugin-cdk/package.json index 6392ecdae440f..0d07037e93385 100644 --- a/tools/eslint-plugin-cdk/package.json +++ b/tools/eslint-plugin-cdk/package.json @@ -12,17 +12,17 @@ "build+test": "npm run build && npm test" }, "devDependencies": { - "@types/eslint": "^7.2.9", + "@types/eslint": "^7.2.10", "@types/fs-extra": "^8.1.1", - "@types/jest": "^26.0.22", - "@types/node": "^10.17.56", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "eslint-plugin-rulesdir": "^0.2.0", "jest": "^26.6.3", "typescript": "~3.9.9" }, "dependencies": { - "@typescript-eslint/parser": "^4.22.0", - "eslint": "^7.24.0", + "@typescript-eslint/parser": "^4.22.1", + "eslint": "^7.26.0", "fs-extra": "^9.1.0" }, "jest": { diff --git a/tools/nodeunit-shim/package.json b/tools/nodeunit-shim/package.json index 58424e094b085..63c784d19321c 100644 --- a/tools/nodeunit-shim/package.json +++ b/tools/nodeunit-shim/package.json @@ -12,8 +12,8 @@ "build+test": "npm run build && npm test" }, "devDependencies": { - "@types/jest": "^26.0.22", - "@types/node": "^10.17.56", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "typescript": "~3.9.9" }, "dependencies": { diff --git a/tools/pkglint/lib/rules.ts b/tools/pkglint/lib/rules.ts index 6919b64fd72e7..3555b4e4d0ae0 100644 --- a/tools/pkglint/lib/rules.ts +++ b/tools/pkglint/lib/rules.ts @@ -1347,7 +1347,7 @@ export class PackageInJsiiPackageNoRuntimeDeps extends ValidationRule { if (Object.keys(innerPkg.dependencies).length > 0) { pkg.report({ ruleName: `${this.name}:1`, - message: `NPM Package '${innerPkg.packageName}' inside jsii package can only have devDependencies`, + message: `NPM Package '${innerPkg.packageName}' inside jsii package '${pkg.packageName}', can only have devDependencies`, }); } @@ -1568,6 +1568,15 @@ export class JestSetup extends ValidationRule { } fileShouldContain(this.name, pkg, '.gitignore', '!jest.config.js'); fileShouldContain(this.name, pkg, '.npmignore', 'jest.config.js'); + + if (!(pkg.json.devDependencies ?? {})['@types/jest']) { + pkg.report({ + ruleName: `${this.name}.types`, + message: 'There must be a devDependency on \'@types/jest\' if you use jest testing', + }); + } + + } } @@ -1626,6 +1635,60 @@ export class UbergenPackageVisibility extends ValidationRule { } /** + * No experimental dependencies. + * In v2 all experimental modules will be released separately from aws-cdk-lib. This means that: + * 1. Stable modules can't depend on experimental modules as it will creates a cyclic dependency. + * 2. Experimental modules shouldn't depend on experimental modules as it will create a coupling between their graduation (cause of 1). + * 2 specify "shouldn't" as in some cases we might allow it (using the `excludedDependencies` map), but the default is to not allow it. + */ +export class NoExperimentalDependents extends ValidationRule { + public name = 'no-experimental-dependencies'; + + // experimental -> experimental dependencies that are allowed for now. + private readonly excludedDependencies = new Map([ + ['@aws-cdk/aws-secretsmanager', ['@aws-cdk/aws-sam']], + ['@aws-cdk/aws-kinesisanalytics-flink', ['@aws-cdk/aws-kinesisanalytics']], + ['@aws-cdk/aws-apigatewayv2-integrations', ['@aws-cdk/aws-apigatewayv2']], + ['@aws-cdk/aws-apigatewayv2-authorizers', ['@aws-cdk/aws-apigatewayv2']], + ['@aws-cdk/aws-events-targets', ['@aws-cdk/aws-kinesisfirehose']], + ]); + + private readonly excludedModules = ['@aws-cdk/cloudformation-include']; + + public validate(pkg: PackageJson): void { + if (this.excludedModules.includes(pkg.packageName)) { + return; + } + if (!isCdkModuleName(pkg.packageName)) { + return; + } + + if (!isIncludedInMonolith(pkg)) { + return; + } + + Object.keys(pkg.dependencies).forEach(dep => { + if (!isCdkModuleName(dep)) { + return; + } + + // eslint-disable-next-line @typescript-eslint/no-require-imports + const stability = require(`${dep}/package.json`).stability; + if (stability === 'experimental') { + if (this.excludedDependencies.get(pkg.packageName)?.includes(dep)) { + return; + } + pkg.report({ + ruleName: this.name, + message: `It is not allowed to depend on experimental modules. ${pkg.packageName} added a dependency on experimental module ${dep}`, + }); + } + }); + } + +} + +/* * Enforces that the aws-cdk-lib README contains all of the core documentation from the @aws-cdk/core README * so users of CDKv2 see all of the core documentation when viewing the aws-cdk-lib docs. */ @@ -1672,7 +1735,7 @@ export class AwsCdkLibReadmeMatchesCore extends ValidationRule { * A package is a JSII package if there is 'jsii' section in the package.json */ function isJSII(pkg: PackageJson): boolean { - return pkg.json.jsii; + return (pkg.json.jsii !== undefined); } /** @@ -1739,3 +1802,17 @@ function cdkMajorVersion() { const releaseJson = require(`${monoRepoRoot()}/release.json`); return releaseJson.majorVersion as number; } + +/** + * Should this package be included in the monolithic package. + */ +function isIncludedInMonolith(pkg: PackageJson): boolean { + if (pkg.json.ubergen?.exclude) { + return false; + } else if (!isJSII(pkg)) { + return false; + } else if (pkg.json.deprecated) { + return false; + } + return true; +} \ No newline at end of file diff --git a/tools/pkglint/package.json b/tools/pkglint/package.json index 24ae6f116a06c..21c682d12b91d 100644 --- a/tools/pkglint/package.json +++ b/tools/pkglint/package.json @@ -37,17 +37,17 @@ "devDependencies": { "@types/fs-extra": "^8.1.1", "@types/glob": "^7.1.3", - "@types/jest": "^26.0.22", - "@types/semver": "^7.3.4", + "@types/jest": "^26.0.23", + "@types/semver": "^7.3.5", "@types/yargs": "^15.0.13", - "@typescript-eslint/eslint-plugin": "^4.21.0", - "@typescript-eslint/parser": "^4.21.0", - "eslint": "^7.23.0", + "@typescript-eslint/eslint-plugin": "^4.22.1", + "@typescript-eslint/parser": "^4.22.1", + "eslint": "^7.26.0", "eslint-import-resolver-node": "^0.3.4", "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-cdk": "0.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.3.4", + "eslint-plugin-jest": "^24.3.6", "jest": "^26.6.3", "typescript": "~3.9.9" }, @@ -58,8 +58,8 @@ "case": "^1.6.3", "colors": "^1.4.0", "fs-extra": "^9.1.0", - "glob": "^7.1.6", - "npm-bundled": "^1.1.1", + "glob": "^7.1.7", + "npm-bundled": "^1.1.2", "semver": "^7.3.5", "yargs": "^16.2.0" } diff --git a/tools/yarn-cling/package.json b/tools/yarn-cling/package.json index 67304ccef2d24..14bb7e2ffef4c 100644 --- a/tools/yarn-cling/package.json +++ b/tools/yarn-cling/package.json @@ -38,10 +38,10 @@ ] }, "devDependencies": { - "@types/jest": "^26.0.22", - "@types/node": "^10.17.56", + "@types/jest": "^26.0.23", + "@types/node": "^10.17.59", "@types/yarnpkg__lockfile": "^1.1.4", - "@types/semver": "^7.3.4", + "@types/semver": "^7.3.5", "jest": "^26.6.3", "pkglint": "0.0.0", "typescript": "~3.9.9" diff --git a/version.v1.json b/version.v1.json index 3a232490b680f..60bdf592f8796 100644 --- a/version.v1.json +++ b/version.v1.json @@ -1,3 +1,3 @@ { - "version": "1.102.0" + "version": "1.103.0" } diff --git a/yarn.lock b/yarn.lock index 52a039d8e542c..cd9959d6a69fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,48 +16,47 @@ dependencies: "@babel/highlight" "^7.12.13" -"@babel/compat-data@^7.13.8": - version "7.13.11" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.11.tgz#9c8fe523c206979c9a81b1e12fe50c1254f1aa35" - integrity sha512-BwKEkO+2a67DcFeS3RLl0Z3Gs2OvdXewuWjc1Hfokhb5eQWP9YRYH1/+VrVZvql2CfjOiNGqSAFOYt4lsqTHzg== +"@babel/compat-data@^7.13.15": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" + integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== "@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.10.tgz#07de050bbd8193fcd8a3c27918c0890613a94559" - integrity sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw== + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.0.tgz#47299ff3ec8d111b493f1a9d04bf88c04e728d88" + integrity sha512-8YqpRig5NmIHlMLw09zMlPTvUVMILjqCOtVgu+TVNWEBvy9b5I3RRyhqnrV4hjgEK7n8P9OqvkWJAFmEL6Wwfw== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.9" - "@babel/helper-compilation-targets" "^7.13.10" - "@babel/helper-module-transforms" "^7.13.0" - "@babel/helpers" "^7.13.10" - "@babel/parser" "^7.13.10" + "@babel/generator" "^7.14.0" + "@babel/helper-compilation-targets" "^7.13.16" + "@babel/helper-module-transforms" "^7.14.0" + "@babel/helpers" "^7.14.0" + "@babel/parser" "^7.14.0" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.1.2" - lodash "^4.17.19" semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.13.0", "@babel/generator@^7.13.9", "@babel/generator@^7.4.0": - version "7.13.9" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39" - integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw== +"@babel/generator@^7.14.0", "@babel/generator@^7.4.0": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.1.tgz#1f99331babd65700183628da186f36f63d615c93" + integrity sha512-TMGhsXMXCP/O1WtQmZjpEYDhCYC9vFhayWZPJSZCGkPJgUqX0rF0wwtrYvnzVxIjcF80tkUertXVk5cwqi5cAQ== dependencies: - "@babel/types" "^7.13.0" + "@babel/types" "^7.14.1" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-compilation-targets@^7.13.10": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz#1310a1678cb8427c07a753750da4f8ce442bdd0c" - integrity sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA== +"@babel/helper-compilation-targets@^7.13.16": + version "7.13.16" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" + integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== dependencies: - "@babel/compat-data" "^7.13.8" + "@babel/compat-data" "^7.13.15" "@babel/helper-validator-option" "^7.12.17" browserslist "^4.14.5" semver "^6.3.0" @@ -78,34 +77,33 @@ dependencies: "@babel/types" "^7.12.13" -"@babel/helper-member-expression-to-functions@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz#6aa4bb678e0f8c22f58cdb79451d30494461b091" - integrity sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ== +"@babel/helper-member-expression-to-functions@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" + integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== dependencies: - "@babel/types" "^7.13.0" + "@babel/types" "^7.13.12" -"@babel/helper-module-imports@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz#ec67e4404f41750463e455cc3203f6a32e93fcb0" - integrity sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g== +"@babel/helper-module-imports@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" + integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.13.12" -"@babel/helper-module-transforms@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz#42eb4bd8eea68bab46751212c357bfed8b40f6f1" - integrity sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw== +"@babel/helper-module-transforms@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.0.tgz#8fcf78be220156f22633ee204ea81f73f826a8ad" + integrity sha512-L40t9bxIuGOfpIGA3HNkJhU9qYrf4y5A5LUSw7rGMSn+pcG8dfJ0g6Zval6YJGd2nEjI7oP00fRdnhLKndx6bw== dependencies: - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-replace-supers" "^7.13.0" - "@babel/helper-simple-access" "^7.12.13" + "@babel/helper-module-imports" "^7.13.12" + "@babel/helper-replace-supers" "^7.13.12" + "@babel/helper-simple-access" "^7.13.12" "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/helper-validator-identifier" "^7.14.0" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" - lodash "^4.17.19" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" "@babel/helper-optimise-call-expression@^7.12.13": version "7.12.13" @@ -119,22 +117,22 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== -"@babel/helper-replace-supers@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz#6034b7b51943094cb41627848cb219cb02be1d24" - integrity sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw== +"@babel/helper-replace-supers@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804" + integrity sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw== dependencies: - "@babel/helper-member-expression-to-functions" "^7.13.0" + "@babel/helper-member-expression-to-functions" "^7.13.12" "@babel/helper-optimise-call-expression" "^7.12.13" "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/types" "^7.13.12" -"@babel/helper-simple-access@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz#8478bcc5cacf6aa1672b251c1d2dde5ccd61a6c4" - integrity sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA== +"@babel/helper-simple-access@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" + integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.13.12" "@babel/helper-split-export-declaration@^7.12.13": version "7.12.13" @@ -143,38 +141,38 @@ dependencies: "@babel/types" "^7.12.13" -"@babel/helper-validator-identifier@^7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" - integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== +"@babel/helper-validator-identifier@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" + integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== -"@babel/helpers@^7.13.10": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8" - integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ== +"@babel/helpers@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" + integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== dependencies: "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" - integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg== + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" + integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/helper-validator-identifier" "^7.14.0" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.4.3": - version "7.13.11" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.11.tgz#f93ebfc99d21c1772afbbaa153f47e7ce2f50b88" - integrity sha512-PhuoqeHoO9fc4ffMEVk4qb/w/s2iOSWohvbHxLtxui0eBg3Lg5gN1U8wp1V1u61hOWkPQJJyJzGH6Y+grwkq8Q== +"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.14.0", "@babel/parser@^7.4.3": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.1.tgz#1bd644b5db3f5797c4479d89ec1817fe02b84c47" + integrity sha512-muUGEKu8E/ftMTPlNp+mc6zL3E9zKWmF5sDHZ5MSsoTP9Wyz64AhEf9kD08xYJ7w6Hdcu8H550ircnPyWSIF0Q== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -269,28 +267,26 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.4.3": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.0.tgz#6d95752475f86ee7ded06536de309a65fc8966cc" - integrity sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.4.3": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.0.tgz#cea0dc8ae7e2b1dec65f512f39f3483e8cc95aef" + integrity sha512-dZ/a371EE5XNhTHomvtuLTUyx6UEoJmYX+DT5zBCQN3McHemsuIaKKYqsc/fs26BEkHs/lBZy0J571LP5z9kQA== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.0" + "@babel/generator" "^7.14.0" "@babel/helper-function-name" "^7.12.13" "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/parser" "^7.14.0" + "@babel/types" "^7.14.0" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" - integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA== +"@babel/types@^7.0.0", "@babel/types@^7.12.13", "@babel/types@^7.13.12", "@babel/types@^7.14.0", "@babel/types@^7.14.1", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.1.tgz#095bd12f1c08ab63eff6e8f7745fa7c9cc15a9db" + integrity sha512-S13Qe85fzLs3gYRUnrpyeIrBJIMYv33qSTg1qoBwiG6nPKwUWAD9odSzWhEedpwOIzSEI6gbdQIWEMiCI42iBA== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" + "@babel/helper-validator-identifier" "^7.14.0" to-fast-properties "^2.0.0" "@balena/dockerignore@^1.0.2": @@ -311,10 +307,10 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@eslint/eslintrc@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547" - integrity sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog== +"@eslint/eslintrc@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.1.tgz#442763b88cecbe3ee0ec7ca6d6dd6168550cbf14" + integrity sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ== dependencies: ajv "^6.12.4" debug "^4.1.1" @@ -513,10 +509,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jsii/spec@^1.28.0": - version "1.28.0" - resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.28.0.tgz#47db1102fc0291dbffffb3adb7f8ee0671e15ef3" - integrity sha512-5mcupuCCXyhZwNmX/RDBn3WUYtd0oPXEDa3E+qOSjT30vaO8u9ZQ+mxwl4qsecx3m51LhXKnR1C9U9t4VlAmqA== +"@jsii/spec@^1.29.0": + version "1.29.0" + resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.29.0.tgz#2378bbacd94e0159c6344c1556af0129e4d3e2f4" + integrity sha512-Y0ouCaYVPy7KjQ8di6Hu4xizKYp4klqqDf08BaEgqd38TzqBuO0abgcd9OJFUQyoDnCCWTdGBfqTo2xfvW9Pbw== dependencies: jsonschema "^1.4.0" @@ -1218,18 +1214,17 @@ integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== "@npmcli/git@^2.0.1": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.0.6.tgz#47b97e96b2eede3f38379262fa3bdfa6eae57bf2" - integrity sha512-a1MnTfeRPBaKbFY07fd+6HugY1WAkKJzdiJvlRub/9o5xz2F/JtPacZZapx5zRJUQFIzSL677vmTSxEcDMrDbg== + version "2.0.9" + resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.0.9.tgz#915bbfe66300e67b4da5ef765a4475ffb2ca5b6b" + integrity sha512-hTMbMryvOqGLwnmMBKs5usbPsJtyEsMsgXwJbmNrsEuQQh1LAIMDU77IoOrwkCg+NgQWl+ySlarJASwM3SutCA== dependencies: - "@npmcli/promise-spawn" "^1.1.0" + "@npmcli/promise-spawn" "^1.3.2" lru-cache "^6.0.0" - mkdirp "^1.0.3" - npm-pick-manifest "^6.0.0" + mkdirp "^1.0.4" + npm-pick-manifest "^6.1.1" promise-inflight "^1.0.1" promise-retry "^2.0.1" - semver "^7.3.2" - unique-filename "^1.1.1" + semver "^7.3.5" which "^2.0.2" "@npmcli/installed-package-contents@^1.0.6": @@ -1253,7 +1248,7 @@ resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== -"@npmcli/promise-spawn@^1.1.0", "@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": +"@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": version "1.3.2" resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== @@ -1261,9 +1256,9 @@ infer-owner "^1.0.4" "@npmcli/run-script@^1.8.2": - version "1.8.4" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.4.tgz#03ced92503a6fe948cbc0975ce39210bc5e824d6" - integrity sha512-Yd9HXTtF1JGDXZw0+SOn+mWLYS0e7bHBHVC/2C8yqs4wUrs/k8rwBSinD7rfk+3WG/MFGRZKxjyoD34Pch2E/A== + version "1.8.5" + resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.5.tgz#f250a0c5e1a08a792d775a315d0ff42fc3a51e1d" + integrity sha512-NQspusBCpTjNwNRFMtz2C5MxoxyzlbuJ4YEhxAKrIonTiirKDtatsZictx9RgamQIx6+QuHMNmPl0wQdoESs9A== dependencies: "@npmcli/node-gyp" "^1.0.2" "@npmcli/promise-spawn" "^1.3.2" @@ -1279,9 +1274,9 @@ "@octokit/types" "^6.0.3" "@octokit/core@^3.2.3": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.3.1.tgz#c6bb6ba171ad84a5f430853a98892cfe8f93d8cd" - integrity sha512-Dc5NNQOYjgZU5S1goN6A/E500yXOfDUFRGQB8/2Tl16AcfvS3H9PudyOe3ZNE/MaVyHPIfC0htReHMJb1tMrvw== + version "3.4.0" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.4.0.tgz#b48aa27d755b339fe7550548b340dcc2b513b742" + integrity sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg== dependencies: "@octokit/auth-token" "^2.4.4" "@octokit/graphql" "^4.5.8" @@ -1309,15 +1304,10 @@ "@octokit/types" "^6.0.3" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^5.3.2": - version "5.3.2" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-5.3.2.tgz#b8ac43c5c3d00aef61a34cf744e315110c78deb4" - integrity sha512-NxF1yfYOUO92rCx3dwvA2onF30Vdlg7YUkMVXkeptqpzA3tRLplThhFleV/UKWFgh7rpKu1yYRbvNDUtzSopKA== - -"@octokit/openapi-types@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-6.0.0.tgz#7da8d7d5a72d3282c1a3ff9f951c8133a707480d" - integrity sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ== +"@octokit/openapi-types@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-7.0.0.tgz#0f6992db9854af15eca77d71ab0ec7fad2f20411" + integrity sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw== "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" @@ -1325,9 +1315,9 @@ integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== "@octokit/plugin-paginate-rest@^2.6.2": - version "2.13.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.2.tgz#7b8244a0dd7a31135ba2adc58a533213837bfe87" - integrity sha512-mjfBcla00UNS4EI/NN7toEbUM45ow3kk4go+LxsXAFLQodsrXcIZbftUhXTqi6ZKd+r6bcqMI+Lv4dshLtFjww== + version "2.13.3" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz#f0f1792230805108762d87906fb02d573b9e070a" + integrity sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg== dependencies: "@octokit/types" "^6.11.0" @@ -1336,20 +1326,12 @@ resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d" integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ== -"@octokit/plugin-rest-endpoint-methods@4.13.5": - version "4.13.5" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.5.tgz#ad76285b82fe05fbb4adf2774a9c887f3534a880" - integrity sha512-kYKcWkFm4Ldk8bZai2RVEP1z97k1C/Ay2FN9FNTBg7JIyKoiiJjks4OtT6cuKeZX39tqa+C3J9xeYc6G+6g8uQ== - dependencies: - "@octokit/types" "^6.12.2" - deprecation "^2.3.1" - -"@octokit/plugin-rest-endpoint-methods@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.0.tgz#cf2cdeb24ea829c31688216a5b165010b61f9a98" - integrity sha512-Jc7CLNUueIshXT+HWt6T+M0sySPjF32mSFQAK7UfAg8qGeRI6OM1GSBxDLwbXjkqy2NVdnqCedJcP1nC785JYg== +"@octokit/plugin-rest-endpoint-methods@5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.1.tgz#631b8d4edc6798b03489911252a25f2a4e58c594" + integrity sha512-vvWbPtPqLyIzJ7A4IPdTl+8IeuKAwMJ4LjvmqWOOdfSuqWQYZXq2CEd0hsnkidff2YfKlguzujHs/reBdAx8Sg== dependencies: - "@octokit/types" "^6.13.0" + "@octokit/types" "^6.13.1" deprecation "^2.3.1" "@octokit/request-error@^2.0.0", "@octokit/request-error@^2.0.5": @@ -1362,57 +1344,38 @@ once "^1.4.0" "@octokit/request@^5.3.0", "@octokit/request@^5.4.12": - version "5.4.14" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.14.tgz#ec5f96f78333bb2af390afa5ff66f114b063bc96" - integrity sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA== + version "5.4.15" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.15.tgz#829da413dc7dd3aa5e2cdbb1c7d0ebe1f146a128" + integrity sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag== dependencies: "@octokit/endpoint" "^6.0.1" "@octokit/request-error" "^2.0.0" "@octokit/types" "^6.7.1" - deprecation "^2.0.0" is-plain-object "^5.0.0" node-fetch "^2.6.1" - once "^1.4.0" universal-user-agent "^6.0.0" -"@octokit/rest@^18.1.0": - version "18.3.5" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.3.5.tgz#a89903d46e0b4273bd3234674ec2777a651d68ab" - integrity sha512-ZPeRms3WhWxQBEvoIh0zzf8xdU2FX0Capa7+lTca8YHmRsO3QNJzf1H3PcuKKsfgp91/xVDRtX91sTe1kexlbw== - dependencies: - "@octokit/core" "^3.2.3" - "@octokit/plugin-paginate-rest" "^2.6.2" - "@octokit/plugin-request-log" "^1.0.2" - "@octokit/plugin-rest-endpoint-methods" "4.13.5" - -"@octokit/rest@^18.5.2": - version "18.5.2" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.5.2.tgz#0369e554b7076e3749005147be94c661c7a5a74b" - integrity sha512-Kz03XYfKS0yYdi61BkL9/aJ0pP2A/WK5vF/syhu9/kY30J8He3P68hv9GRpn8bULFx2K0A9MEErn4v3QEdbZcw== +"@octokit/rest@^18.1.0", "@octokit/rest@^18.5.3": + version "18.5.3" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.5.3.tgz#6a2e6006a87ebbc34079c419258dd29ec9ff659d" + integrity sha512-KPAsUCr1DOdLVbZJgGNuE/QVLWEaVBpFQwDAz/2Cnya6uW2wJ/P5RVGk0itx7yyN1aGa8uXm2pri4umEqG1JBA== dependencies: "@octokit/core" "^3.2.3" "@octokit/plugin-paginate-rest" "^2.6.2" "@octokit/plugin-request-log" "^1.0.2" - "@octokit/plugin-rest-endpoint-methods" "5.0.0" + "@octokit/plugin-rest-endpoint-methods" "5.0.1" -"@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.12.2", "@octokit/types@^6.7.1": - version "6.12.2" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.12.2.tgz#5b44add079a478b8eb27d78cf384cc47e4411362" - integrity sha512-kCkiN8scbCmSq+gwdJV0iLgHc0O/GTPY1/cffo9kECu1MvatLPh9E+qFhfRIktKfHEA6ZYvv6S1B4Wnv3bi3pA== +"@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.13.1", "@octokit/types@^6.7.1": + version "6.14.2" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.14.2.tgz#64c9457f38fb8522bdbba3c8cc814590a2d61bf5" + integrity sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA== dependencies: - "@octokit/openapi-types" "^5.3.2" - -"@octokit/types@^6.13.0": - version "6.13.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.13.0.tgz#779e5b7566c8dde68f2f6273861dd2f0409480d0" - integrity sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA== - dependencies: - "@octokit/openapi-types" "^6.0.0" + "@octokit/openapi-types" "^7.0.0" "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.2.tgz#858f5c4b48d80778fde4b9d541f27edc0d56488b" - integrity sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw== + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== dependencies: type-detect "4.0.8" @@ -1449,20 +1412,15 @@ dependencies: "@types/glob" "*" -"@types/aws-lambda@^8.10.62": +"@types/aws-lambda@^8.10.76": version "8.10.76" resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.76.tgz#a20191677f1f5e32fe1f26739b1d6fbbea9cf636" integrity sha512-lCTyeRm3NWqSwDnoji0z82Pl0tsOpr1p+33AiNeidgarloWXh3wdiVRUuxEa+sY9S5YLOYGz5X3N3Zvpibvm5w== -"@types/aws-lambda@^8.10.75": - version "8.10.75" - resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.75.tgz#93b4e688db8a45755018561a3212e7766c0fef57" - integrity sha512-orOKSsIVUMsAbKgbSX2ST3FwQt9pxinHVCAIAVl4SmmTxmki2Gu+cGqobMD3eYwDV5FV0YNtaXyxnvE9pLrKTw== - "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": - version "7.1.13" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.13.tgz#bc6eea53975fdf163aff66c086522c6f293ae4cf" - integrity sha512-CC6amBNND16pTk4K3ZqKIaba6VGKAQs3gMjEY17FVd56oI/ZWt9OhS6riYiWv9s8ENbYUi7p8lgqb0QHQvUKQQ== + version "7.1.14" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402" + integrity sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -1492,18 +1450,18 @@ dependencies: "@babel/types" "^7.3.0" -"@types/eslint@^7.2.9": - version "7.2.9" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.9.tgz#5d26eadbb6d04a225967176399a18eff622da982" - integrity sha512-SdAAXZNvWfhtf3X3y1cbbCZhP3xyPh7mfTvzV6CgfWc/ZhiHpyr9bVroe2/RCHIf7gczaNcprhaBLsx0CCJHQA== +"@types/eslint@^7.2.10": + version "7.2.10" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.10.tgz#4b7a9368d46c0f8cd5408c23288a59aa2394d917" + integrity sha512-kUEPnMKrqbtpCq/KTaGFFKAcz6Ethm2EjCoKIDaCmfRBWLbFuTcOJfTlorwbnboXBzahqWLgUp1BQeKHiJzPUQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" "@types/estree@*": - version "0.0.46" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe" - integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== + version "0.0.47" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4" + integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg== "@types/fs-extra@^8.1.1": version "8.1.1" @@ -1546,7 +1504,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.14": +"@types/jest@^26.0.23": version "26.0.23" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.23.tgz#a1b7eab3c503b80451d019efb588ec63522ee4e7" integrity sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA== @@ -1554,14 +1512,6 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/jest@^26.0.22": - version "26.0.22" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.22.tgz#8308a1debdf1b807aa47be2838acdcd91e88fbe6" - integrity sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw== - dependencies: - jest-diff "^26.0.0" - pretty-format "^26.0.0" - "@types/json-schema@*", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.7": version "7.0.7" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" @@ -1591,12 +1541,7 @@ dependencies: "@types/node" "*" -"@types/minimatch@*", "@types/minimatch@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/minimatch@^3.0.4": +"@types/minimatch@*", "@types/minimatch@^3.0.3", "@types/minimatch@^3.0.4": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== @@ -1618,15 +1563,20 @@ resolved "https://registry.yarnpkg.com/@types/mockery/-/mockery-1.4.29.tgz#9ba22df37f07e3780fff8531d1a38e633f9457a5" integrity sha1-m6It838H43gP/4Ux0aOOYz+UV6U= -"@types/node@*", "@types/node@^14.14.33": - version "14.14.35" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313" - integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag== +"@types/node@*": + version "15.0.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.2.tgz#51e9c0920d1b45936ea04341aa3e2e58d339fb67" + integrity sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA== + +"@types/node@^10.17.59": + version "10.17.59" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.59.tgz#03f440ccf746a27f7da6e141e6cbae64681dbd2f" + integrity sha512-7Uc8IRrL8yZz5ti45RaFxpbU8TxlzdC3HvxV+hOWo1EyLsuKv/w7y0n+TwZzwL3vdx3oZ2k3ubxPq131hNtXyg== -"@types/node@^10.17.56": - version "10.17.56" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.56.tgz#010c9e047c3ff09ddcd11cbb6cf5912725cdc2b3" - integrity sha512-LuAa6t1t0Bfw4CuSR0UITsm1hP17YL+u82kfHGrHUWdhlBtH7sa7jGY5z7glGaIj/WDYDkRtgGd+KCjCzxBW1w== +"@types/node@^14.14.33": + version "14.14.44" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.44.tgz#df7503e6002847b834371c004b372529f3f85215" + integrity sha512-+gaugz6Oce6ZInfI/tK4Pq5wIIkJMEJUu92RB3Eu93mtj4wjjjz9EB5mLp5s1pSsLXdC/CPut/xF20ZzAQJbTA== "@types/nodeunit@^0.0.31": version "0.0.31" @@ -1665,10 +1615,10 @@ resolved "https://registry.yarnpkg.com/@types/punycode/-/punycode-2.1.0.tgz#89e4f3d09b3f92e87a80505af19be7e0c31d4e83" integrity sha512-PG5aLpW6PJOeV2fHRslP4IOMWn+G+Uq8CfnyJ+PDS8ndCbU+soO+fB3NKCKo0p/Jh2Y4aPaiQZsrOXFdzpcA6g== -"@types/semver@^7.3.4": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb" - integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ== +"@types/semver@^7.3.5": + version "7.3.5" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.5.tgz#74deebbbcb1e86634dbf10a5b5e8798626f5a597" + integrity sha512-iotVxtCCsPLRAvxMFFgxL8HD2l4mAZ2Oin7/VJ2ooWO0VOK4EGOGmZWZn1uCq7RofR3I/1IOSjCHlFT71eVK0Q== "@types/sinon@^9.0.11": version "9.0.11" @@ -1695,9 +1645,11 @@ string-width "*" "@types/table@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@types/table/-/table-6.0.0.tgz#c3e8f1e0d80525036a7655fd650409e0230f1ead" - integrity sha512-RSmRiYetRzpcZcgNo4x6C1VSsPGBHCGGDO7Rbnz5esVLbGONxBP1CUcn8JhAkVzUVLO+AY8yOSkb27jvfauLyg== + version "6.3.2" + resolved "https://registry.yarnpkg.com/@types/table/-/table-6.3.2.tgz#e18ad2594400d81c3da28c31b342eb5a0d87a8e7" + integrity sha512-GJ82z3vQbx2BhiUo12w2A3lyBpXPJrGHjQ7iS5aH925098w8ojqiWBhgOUy97JS2PKLmRCTLT0sI+gJI4futig== + dependencies: + table "*" "@types/uuid@^8.3.0": version "8.3.0" @@ -1740,13 +1692,13 @@ resolved "https://registry.yarnpkg.com/@types/yarnpkg__lockfile/-/yarnpkg__lockfile-1.1.4.tgz#445251eb00bd9c1e751f82c7c6bf4f714edfd464" integrity sha512-/emrKCfQMQmFCqRqqBJ0JueHBT06jBRM3e8OgnvDUcvuExONujIk2hFA5dNsN9Nt41ljGVDdChvCydATZ+KOZw== -"@typescript-eslint/eslint-plugin@^4.21.0", "@typescript-eslint/eslint-plugin@^4.22.0": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz#3d5f29bb59e61a9dba1513d491b059e536e16dbc" - integrity sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA== +"@typescript-eslint/eslint-plugin@^4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.1.tgz#6bcdbaa4548553ab861b4e5f34936ead1349a543" + integrity sha512-kVTAghWDDhsvQ602tHBc6WmQkdaYbkcTwZu+7l24jtJiYvm9l+/y/b2BZANEezxPDiX5MK2ZecE+9BFi/YJryw== dependencies: - "@typescript-eslint/experimental-utils" "4.22.0" - "@typescript-eslint/scope-manager" "4.22.0" + "@typescript-eslint/experimental-utils" "4.22.1" + "@typescript-eslint/scope-manager" "4.22.1" debug "^4.1.1" functional-red-black-tree "^1.0.1" lodash "^4.17.15" @@ -1754,106 +1706,60 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.22.0": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz#68765167cca531178e7b650a53456e6e0bef3b1f" - integrity sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg== +"@typescript-eslint/experimental-utils@4.22.1", "@typescript-eslint/experimental-utils@^4.0.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.1.tgz#3938a5c89b27dc9a39b5de63a62ab1623ab27497" + integrity sha512-svYlHecSMCQGDO2qN1v477ax/IDQwWhc7PRBiwAdAMJE7GXk5stF4Z9R/8wbRkuX/5e9dHqbIWxjeOjckK3wLQ== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.22.0" - "@typescript-eslint/types" "4.22.0" - "@typescript-eslint/typescript-estree" "4.22.0" + "@typescript-eslint/scope-manager" "4.22.1" + "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/typescript-estree" "4.22.1" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/experimental-utils@^4.0.1": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.18.0.tgz#ed6c955b940334132b17100d2917449b99a91314" - integrity sha512-92h723Kblt9JcT2RRY3QS2xefFKar4ZQFVs3GityOKWQYgtajxt/tuXIzL7sVCUlM1hgreiV5gkGYyBpdOwO6A== +"@typescript-eslint/parser@^4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.22.1.tgz#a95bda0fd01d994a15fc3e99dc984294f25c19cc" + integrity sha512-l+sUJFInWhuMxA6rtirzjooh8cM/AATAe3amvIkqKFeMzkn85V+eLzb1RyuXkHak4dLfYzOmF6DXPyflJvjQnw== dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.18.0" - "@typescript-eslint/types" "4.18.0" - "@typescript-eslint/typescript-estree" "4.18.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^4.21.0", "@typescript-eslint/parser@^4.22.0": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.22.0.tgz#e1637327fcf796c641fe55f73530e90b16ac8fe8" - integrity sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q== - dependencies: - "@typescript-eslint/scope-manager" "4.22.0" - "@typescript-eslint/types" "4.22.0" - "@typescript-eslint/typescript-estree" "4.22.0" + "@typescript-eslint/scope-manager" "4.22.1" + "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/typescript-estree" "4.22.1" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.18.0.tgz#d75b55234c35d2ff6ac945758d6d9e53be84a427" - integrity sha512-olX4yN6rvHR2eyFOcb6E4vmhDPsfdMyfQ3qR+oQNkAv8emKKlfxTWUXU5Mqxs2Fwe3Pf1BoPvrwZtwngxDzYzQ== - dependencies: - "@typescript-eslint/types" "4.18.0" - "@typescript-eslint/visitor-keys" "4.18.0" - -"@typescript-eslint/scope-manager@4.22.0": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz#ed411545e61161a8d702e703a4b7d96ec065b09a" - integrity sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q== +"@typescript-eslint/scope-manager@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.22.1.tgz#5bb357f94f9cd8b94e6be43dd637eb73b8f355b4" + integrity sha512-d5bAiPBiessSmNi8Amq/RuLslvcumxLmyhf1/Xa9IuaoFJ0YtshlJKxhlbY7l2JdEk3wS0EnmnfeJWSvADOe0g== dependencies: - "@typescript-eslint/types" "4.22.0" - "@typescript-eslint/visitor-keys" "4.22.0" + "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/visitor-keys" "4.22.1" -"@typescript-eslint/types@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.18.0.tgz#bebe323f81f2a7e2e320fac9415e60856267584a" - integrity sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A== +"@typescript-eslint/types@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.22.1.tgz#bf99c6cec0b4a23d53a61894816927f2adad856a" + integrity sha512-2HTkbkdAeI3OOcWbqA8hWf/7z9c6gkmnWNGz0dKSLYLWywUlkOAQ2XcjhlKLj5xBFDf8FgAOF5aQbnLRvgNbCw== -"@typescript-eslint/types@4.22.0": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.22.0.tgz#0ca6fde5b68daf6dba133f30959cc0688c8dd0b6" - integrity sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA== - -"@typescript-eslint/typescript-estree@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz#756d3e61da8c16ab99185532c44872f4cd5538cb" - integrity sha512-wt4xvF6vvJI7epz+rEqxmoNQ4ZADArGQO9gDU+cM0U5fdVv7N+IAuVoVAoZSOZxzGHBfvE3XQMLdy+scsqFfeg== +"@typescript-eslint/typescript-estree@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.1.tgz#dca379eead8cdfd4edc04805e83af6d148c164f9" + integrity sha512-p3We0pAPacT+onSGM+sPR+M9CblVqdA9F1JEdIqRVlxK5Qth4ochXQgIyb9daBomyQKAXbygxp1aXQRV0GC79A== dependencies: - "@typescript-eslint/types" "4.18.0" - "@typescript-eslint/visitor-keys" "4.18.0" + "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/visitor-keys" "4.22.1" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@4.22.0": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz#b5d95d6d366ff3b72f5168c75775a3e46250d05c" - integrity sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg== - dependencies: - "@typescript-eslint/types" "4.22.0" - "@typescript-eslint/visitor-keys" "4.22.0" - debug "^4.1.1" - globby "^11.0.1" - is-glob "^4.0.1" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/visitor-keys@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz#4e6fe2a175ee33418318a029610845a81e2ff7b6" - integrity sha512-Q9t90JCvfYaN0OfFUgaLqByOfz8yPeTAdotn/XYNm5q9eHax90gzdb+RJ6E9T5s97Kv/UHWKERTmqA0jTKAEHw== - dependencies: - "@typescript-eslint/types" "4.18.0" - eslint-visitor-keys "^2.0.0" - -"@typescript-eslint/visitor-keys@4.22.0": - version "4.22.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz#169dae26d3c122935da7528c839f42a8a42f6e47" - integrity sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw== +"@typescript-eslint/visitor-keys@4.22.1": + version "4.22.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.1.tgz#6045ae25a11662c671f90b3a403d682dfca0b7a6" + integrity sha512-WPkOrIRm+WCLZxXQHCi+WG8T2MMTUFR70rWjdWYddLT7cEfb2P4a3O/J2U1FBVsSFTocXLCoXWY6MZGejeStvQ== dependencies: - "@typescript-eslint/types" "4.22.0" + "@typescript-eslint/types" "4.22.1" eslint-visitor-keys "^2.0.0" "@yarnpkg/lockfile@^1.1.0": @@ -1869,7 +1775,7 @@ JSONStream@^1.0.4: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^2.0.3: +abab@^2.0.3, abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== @@ -1902,6 +1808,11 @@ acorn@^7.1.1, acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.1.0: + version "8.2.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.4.tgz#caba24b08185c3b56e3168e97d15ed17f4d31fd0" + integrity sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" @@ -1941,20 +1852,10 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^7.0.2: - version "7.2.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.2.1.tgz#a5ac226171912447683524fa2f1248fcf8bac83d" - integrity sha512-+nu0HDv7kNSOua9apAVc979qd932rrZeb3WOvoiD31A/p1mIE5/9bN2027pE2rOPYEdS3UHzsvof4hY+lM9/WQ== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - ajv@^8.0.1: - version "8.0.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.0.2.tgz#1396e27f208ed56dd5638ab5a251edeb1c91d402" - integrity sha512-V0HGxJd0PiDF0ecHYIesTOqfd1gJguwQUOYfMfAWnRsWQEXfc5ifbUFhD3Wjc+O+y7VAqL+g07prq9gHQ/JOZQ== + version "8.3.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.3.0.tgz#25ee7348e32cdc4a1dbb38256bf6bdc451dd577c" + integrity sha512-RYE7B5An83d7eWnDR8kbdaIFqmKCNsP16ay1hDbJEU+sa0e3H9SebskCt0Uufem6cfAVu7Col6ubcn/W+Sm8/Q== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -1967,22 +1868,17 @@ ansi-colors@^4.1.1: integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-escapes@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" - integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: - type-fest "^0.11.0" + type-fest "^0.21.3" ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -2016,9 +1912,9 @@ anymatch@^2.0.0: normalize-path "^2.1.1" anymatch@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -2257,9 +2153,9 @@ aws-sdk-mock@^5.1.0: traverse "^0.6.6" aws-sdk@^2.596.0, aws-sdk@^2.637.0, aws-sdk@^2.848.0: - version "2.866.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.866.0.tgz#8150fb2e0cfecd281968edee7cad84598d8d7a09" - integrity sha512-6Z581Ek2Yfm78NpeEFMNuSoyiYG7tipEaqfWNFR1AGyYheZwql4ajhzzlpWn91LBpdm7qcFldSNY9U0tKpKWNw== + version "2.903.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.903.0.tgz#4c8252723370ebbdaffe69f4dfddc5973b1dab4a" + integrity sha512-BP/giYLP8QJ63Jta59kph1F76oPITxRt/wNr3BdoEs9BtshWlGKk149UaseDB4wJtI+0TER5jtzBIUBcP6E+wA== dependencies: buffer "4.9.2" events "1.1.1" @@ -2350,9 +2246,9 @@ babel-preset-jest@^26.6.2: babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" @@ -2380,14 +2276,14 @@ bcrypt-pbkdf@^1.0.0: tweetnacl "^0.14.3" before-after-hook@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.0.tgz#09c40d92e936c64777aa385c4e9b904f8147eaf0" - integrity sha512-jH6rKQIfroBbhEXVmI7XmXe3ix5S/PgJqpzdDPnR8JGLHWNYLsYZ6tK5iWOF/Ra3oqEX0NobXGlzbiylIzVphQ== + version "2.2.1" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.1.tgz#73540563558687586b52ed217dad6a802ab1549c" + integrity sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw== bind-obj-methods@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/bind-obj-methods/-/bind-obj-methods-2.0.1.tgz#1c1295d6741c07b78d15f42080fe4a60a27f91f5" - integrity sha512-kKzUyCuc+jsWH4C2nW5KB2nh+rQRbQcdphfo9UN3j1uwIFGZ3JB8njtRZOiUAQCkxazH0nDQPN6x/zhvFcbZIw== + version "2.0.2" + resolved "https://registry.yarnpkg.com/bind-obj-methods/-/bind-obj-methods-2.0.2.tgz#ea603b0f2455dce76d177c69747751b40c815897" + integrity sha512-bUkRdEOppT1Xg/jG0+bp0JSjUD9U0r7skxb/42WeBUjfBpW6COQTIgQmKX5J2Z3aMXcORKgN2N+d7IQwTK3pag== bl@^4.0.3: version "4.1.0" @@ -2440,15 +2336,15 @@ browser-process-hrtime@^1.0.0: integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== browserslist@^4.14.5: - version "4.16.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717" - integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw== + version "4.16.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" + integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== dependencies: - caniuse-lite "^1.0.30001181" - colorette "^1.2.1" - electron-to-chromium "^1.3.649" + caniuse-lite "^1.0.30001219" + colorette "^1.2.2" + electron-to-chromium "^1.3.723" escalade "^3.1.1" - node-releases "^1.1.70" + node-releases "^1.1.71" bs-logger@0.x: version "0.2.6" @@ -2512,9 +2408,9 @@ bytes@3.1.0: integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== cacache@^15.0.5: - version "15.0.5" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0" - integrity sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A== + version "15.0.6" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.6.tgz#65a8c580fda15b59150fb76bf3f3a8e45d583099" + integrity sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w== dependencies: "@npmcli/move-file" "^1.0.1" chownr "^2.0.0" @@ -2530,7 +2426,7 @@ cacache@^15.0.5: p-map "^4.0.0" promise-inflight "^1.0.1" rimraf "^3.0.2" - ssri "^8.0.0" + ssri "^8.0.1" tar "^6.0.2" unique-filename "^1.1.1" @@ -2614,10 +2510,10 @@ camelcase@^6.0.0, camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -caniuse-lite@^1.0.30001181: - version "1.0.30001202" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001202.tgz#4cb3bd5e8a808e8cd89e4e66c549989bc8137201" - integrity sha512-ZcijQNqrcF8JNLjzvEiXqX4JUYxoZa7Pvcsd9UD8Kz4TvhTonOSNRsK+qtvpVL4l6+T1Rh4LFtLfnNWg6BGWCQ== +caniuse-lite@^1.0.30001219: + version "1.0.30001228" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" + integrity sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A== capture-exit@^2.0.0: version "2.0.0" @@ -2667,9 +2563,9 @@ chalk@^2.0.0, chalk@^2.4.2: supports-color "^5.3.0" chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + version "4.1.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" + integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" @@ -2806,15 +2702,10 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/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.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -codemaker@^1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.28.0.tgz#21237f9240ab05ecca6c65da48141b8b752539b8" - integrity sha512-TlpvV3q/68cZk7aljYW6b/5EvyB4uw523xJISTATrCrQu/UTA79/mxpA2ug8uhPcJoGYcfWXH4BHVVLNIuEtrg== +codemaker@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/codemaker/-/codemaker-1.29.0.tgz#c262d1149681348103c7a79913a9a39ba13098f5" + integrity sha512-dNUTiOhxNYB7MV75bLLCie1gr0SUh6wEOPc5OyZob4mLj51OETYIeRYILEiz39QVKLRx6YSbKoCY/S4PqQ0PNQ== dependencies: camelcase "^6.2.0" decamelize "^5.0.0" @@ -2862,7 +2753,7 @@ color-support@^1.1.0: resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -colorette@^1.2.1: +colorette@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== @@ -2959,9 +2850,9 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= constructs@^3.3.69: - version "3.3.71" - resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.71.tgz#5a3e968de484ad327bc2650aa4a7f37a39834ac5" - integrity sha512-3KFtTsA7OV27m/+pJhN4iJkKzHbPIPvyvEX5BQ/JCAWjfCHOQEVpIgxHLpT4i8L1OFta+pJrzcEVAHo6UitwqA== + version "3.3.75" + resolved "https://registry.yarnpkg.com/constructs/-/constructs-3.3.75.tgz#222516951fd6b8380cb6fea3c171eeca0bf980a4" + integrity sha512-q10foASSSfDWmS99OQLfnWDXCzqLvoORISAVWPFg0AmIGlBv2ZdDOtXxLqrJARPxVlOldmW2JzWzdRI+4+0/ZA== contains-path@^0.1.0: version "0.1.0" @@ -3006,7 +2897,7 @@ conventional-changelog-config-spec@2.1.0: resolved "https://registry.yarnpkg.com/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz#874a635287ef8b581fd8558532bf655d4fb59f2d" integrity sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ== -conventional-changelog-conventionalcommits@4.5.0, conventional-changelog-conventionalcommits@^4.5.0: +conventional-changelog-conventionalcommits@4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz#a02e0b06d11d342fdc0f00c91d78265ed0bc0a62" integrity sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw== @@ -3015,6 +2906,15 @@ conventional-changelog-conventionalcommits@4.5.0, conventional-changelog-convent lodash "^4.17.15" q "^1.5.1" +conventional-changelog-conventionalcommits@^4.5.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.0.tgz#7fc17211dbca160acf24687bd2fdd5fd767750eb" + integrity sha512-sj9tj3z5cnHaSJCYObA9nISf7eq/YjscLPoq6nmew4SiOjxqL2KRpK20fjnjVbpNDjJ2HR3MoVcWKXwbVvzS0A== + dependencies: + compare-func "^2.0.0" + lodash "^4.17.15" + q "^1.5.1" + conventional-changelog-core@^4.2.1, conventional-changelog-core@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.2.tgz#f0897df6d53b5d63dec36b9442bd45354f8b3ce5" @@ -3259,7 +3159,7 @@ cssom@~0.3.6: resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^2.2.0: +cssstyle@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== @@ -3351,7 +3251,7 @@ decamelize@^5.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.0.tgz#88358157b010ef133febfd27c18994bd80c6215b" integrity sha512-U75DcT5hrio3KNtvdULAWnLiAPbFUC4191ldxMmj4FA/mRuBnmDwU0boNfPyFRhnan+Jm+haLeSn3P0afcBn4w== -decimal.js@^10.2.0: +decimal.js@^10.2.1: version "10.2.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== @@ -3590,9 +3490,9 @@ dotenv-json@^1.0.0: integrity sha512-jAssr+6r4nKhKRudQ0HOzMskOFFi9+ubXWwmrSGJFgTvpjyPXCXsCsYbjif6mXp7uxA7xY3/LGaiTQukZzSbOQ== dotenv@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== dotgitignore@^2.1.0: version "2.1.0" @@ -3627,21 +3527,16 @@ ejs@^2.5.2: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== -electron-to-chromium@^1.3.649: - version "1.3.691" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.691.tgz#a671eaf135a3ccec0915eb8d844a0952aba79f3b" - integrity sha512-ZqiO69KImmOGCyoH0icQPU3SndJiW93juEvf63gQngyhODO6SpQIPMTOHldtCs5DS5GMKvAkquk230E2zt2vpw== +electron-to-chromium@^1.3.723: + version "1.3.727" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.727.tgz#857e310ca00f0b75da4e1db6ff0e073cc4a91ddf" + integrity sha512-Mfz4FIB4FSvEwBpDfdipRIrwd6uo8gUDoRDF4QEYb4h4tSuI3ov594OrjU6on042UlFHouIJpClDODGkPcBSbg== emittery@^0.7.1: version "0.7.2" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -3684,9 +3579,9 @@ env-paths@^2.2.0: integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== envinfo@^7.7.4: - version "7.7.4" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.4.tgz#c6311cdd38a0e86808c1c9343f667e4267c4a320" - integrity sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ== + version "7.8.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== err-code@^2.0.2: version "2.0.3" @@ -3755,10 +3650,10 @@ es6-error@^4.0.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.10.tgz#f5d39e4d9cc130b78d751664fef1b663240f5545" - integrity sha512-XvGbf+UreVFA24Tlk6sNOqNcvF2z49XAZt4E7A4H80+yqn944QOLTTxaU0lkdYNtZKFiITNea+VxmtrfjvnLPA== +esbuild@^0.11.20: + version "0.11.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.20.tgz#7cefa1aee8b372c184e42457885f7ce5d3e62a1e" + integrity sha512-QOZrVpN/Yz74xfat0H6euSgn3RnwLevY1mJTEXneukz1ln9qB+ieaerRMzSeETpz/UJWsBMzRVR/andBht5WKw== escalade@^3.1.1: version "3.1.1" @@ -3780,7 +3675,7 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escodegen@^1.14.1, escodegen@^1.8.1: +escodegen@^1.8.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -3792,6 +3687,18 @@ escodegen@^1.14.1, escodegen@^1.8.1: optionalDependencies: source-map "~0.6.1" +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-config-standard@^14.1.1: version "14.1.1" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" @@ -3851,10 +3758,10 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@^24.3.4, eslint-plugin-jest@^24.3.5: - version "24.3.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.5.tgz#71f0b580f87915695c286c3f0eb88cf23664d044" - integrity sha512-XG4rtxYDuJykuqhsOqokYIR84/C8pRihRtEpVskYLbIIKGwPNW2ySxdctuVzETZE+MbF/e7wmsnbNVpzM0rDug== +eslint-plugin-jest@^24.3.6: + version "24.3.6" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.6.tgz#5f0ca019183c3188c5ad3af8e80b41de6c8e9173" + integrity sha512-WOVH4TIaBLIeCX576rLcOgjNXqP+jNlCiEmRgFTfQtJ52DpwnIQKAVGlGPAN7CZ33bW6eNfHD6s8ZbEUTQubJg== dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" @@ -3906,17 +3813,17 @@ eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== eslint-visitor-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" - integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@^7.23.0, eslint@^7.24.0: - version "7.24.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.24.0.tgz#2e44fa62d93892bfdb100521f17345ba54b8513a" - integrity sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ== +eslint@^7.26.0: + version "7.26.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.26.0.tgz#d416fdcdcb3236cd8f282065312813f8c13982f6" + integrity sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg== dependencies: "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.0" + "@eslint/eslintrc" "^0.4.1" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -4017,9 +3924,9 @@ events@1.1.1: integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= exec-sh@^0.3.2: - version "0.3.4" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" - integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + version "0.3.6" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== execa@^1.0.0: version "1.0.0" @@ -4348,9 +4255,9 @@ flatted@^3.1.0: integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== follow-redirects@^1.10.0, follow-redirects@^1.11.0: - version "1.13.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267" - integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA== + version "1.14.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" + integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== for-in@^1.0.2: version "1.0.2" @@ -4575,9 +4482,9 @@ get-stream@^5.0.0: pump "^3.0.0" get-stream@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" - integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== get-uri@3: version "3.0.2" @@ -4669,10 +4576,10 @@ glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1: dependencies: is-glob "^4.0.1" -glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7, glob@~7.1.6: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -4694,16 +4601,16 @@ globals@^12.1.0: type-fest "^0.8.1" globals@^13.6.0: - version "13.6.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.6.0.tgz#d77138e53738567bb96a3916ff6f6b487af20ef7" - integrity sha512-YFKCX0SiPg7l5oKYCJ2zZGxcXprVXHcSnVuvzrT3oSENQonVLqM5pf9fN5dLGZGyCjhw8TN8Btwe/jKnZ0pjvQ== + version "13.8.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.8.0.tgz#3e20f504810ce87a8d72e55aecf8435b50f4c1b3" + integrity sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q== dependencies: type-fest "^0.20.2" globby@^11.0.1, globby@^11.0.2: - version "11.0.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" - integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== + version "11.0.3" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb" + integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" @@ -4752,7 +4659,7 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -has-bigints@^1.0.0: +has-bigints@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== @@ -4767,7 +4674,7 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.0, has-symbols@^1.0.1, has-symbols@^1.0.2: +has-symbols@^1.0.1, has-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== @@ -4836,21 +4743,14 @@ hasha@^5.0.0: integrity sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw= hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== - -hosted-git-info@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.0.tgz#9f06639a90beff66cacae6e77f8387b431d61ddc" - integrity sha512-fqhGdjk4av7mT9fU/B01dUtZ+WZSc/XEXMoLXDVZukiQRXxeHSSz3AqbeWRJHtF8EQYHlAgB1NSAHU0Cm7aqZA== - dependencies: - lru-cache "^6.0.0" + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== hosted-git-info@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.1.tgz#710ef5452ea429a844abc33c981056e7371edab7" - integrity sha512-eT7NrxAsppPRQEBSwKSosReE+v8OzABwEScQYk5d4uxaEPlzxTIku7LINXtBGalthkLhJnq5lBI89PfK43zAKg== + version "4.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" + integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg== dependencies: lru-cache "^6.0.0" @@ -4950,9 +4850,9 @@ ieee754@^1.1.13, ieee754@^1.1.4: integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore-walk@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== + version "3.0.4" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" + integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== dependencies: minimatch "^3.0.4" @@ -5028,16 +4928,16 @@ ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== init-package-json@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.2.tgz#d81a7e6775af9b618f20bba288e440b8d1ce05f3" - integrity sha512-PO64kVeArePvhX7Ff0jVWkpnE1DfGRvaWcStYrPugcJz9twQGYibagKJuIMHCX7ENcp0M6LJlcjLBuLD5KeJMg== + version "2.0.3" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.3.tgz#c8ae4f2a4ad353bcbc089e5ffe98a8f1a314e8fd" + integrity sha512-tk/gAgbMMxR6fn1MgMaM1HpU1ryAmBWWitnxG5OhuNXeX0cbpbgV5jA4AIpQJVNoyOfOevTtO6WX+rPs+EFqaQ== dependencies: glob "^7.1.1" - npm-package-arg "^8.1.0" + npm-package-arg "^8.1.2" promzard "^0.3.0" read "~1.0.1" - read-package-json "^3.0.0" - semver "^7.3.2" + read-package-json "^3.0.1" + semver "^7.3.5" validate-npm-package-license "^3.0.4" validate-npm-package-name "^3.0.0" @@ -5065,11 +4965,6 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= - ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -5102,16 +4997,16 @@ is-arrayish@^0.2.1: integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-bigint@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.1.tgz#6923051dfcbc764278540b9ce0e6b3213aa5ebc2" - integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" + integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== is-boolean-object@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.0.tgz#e2aaad3a3a8fca34c28f6eee135b156ed2587ff0" - integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA== + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" + integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" is-buffer@^1.1.5, is-buffer@~1.1.6: version "1.1.6" @@ -5131,9 +5026,9 @@ is-ci@^2.0.0: ci-info "^2.0.0" is-core-module@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" - integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== + version "2.4.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" + integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== dependencies: has "^1.0.3" @@ -5152,9 +5047,9 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1, is-date-object@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5" + integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A== is-descriptor@^0.1.0: version "0.1.6" @@ -5175,9 +5070,9 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: kind-of "^6.0.2" is-docker@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" - integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" @@ -5201,18 +5096,6 @@ is-finite@^1.0.0: resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/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.yarnpkg.com/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.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -5246,9 +5129,9 @@ is-negative-zero@^2.0.1: integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" + integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw== is-number@^3.0.0: version "3.0.0" @@ -5295,17 +5178,17 @@ is-plain-object@^5.0.0: integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== is-potential-custom-element-name@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" - integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== is-regex@^1.1.1, is-regex@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" - integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" + integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== dependencies: call-bind "^1.0.2" - has-symbols "^1.0.1" + has-symbols "^1.0.2" is-set@^2.0.1, is-set@^2.0.2: version "2.0.2" @@ -5330,16 +5213,16 @@ is-stream@^2.0.0: integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" + integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: - has-symbols "^1.0.1" + has-symbols "^1.0.2" is-text-path@^1.0.1: version "1.0.1" @@ -5958,9 +5841,9 @@ js-yaml@^3.13.1, js-yaml@^3.2.7: esprima "^4.0.0" js-yaml@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f" - integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q== + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" @@ -5970,35 +5853,35 @@ jsbn@~0.1.0: integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsdom@^16.4.0: - version "16.4.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb" - integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w== + version "16.5.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.5.3.tgz#13a755b3950eb938b4482c407238ddf16f0d2136" + integrity sha512-Qj1H+PEvUsOtdPJ056ewXM4UJPCi4hhLA8wpiz9F2YvsRBhuFsXxtrIFAgGBDynQA9isAMGE91PfUYbdMPXuTA== dependencies: - abab "^2.0.3" - acorn "^7.1.1" + abab "^2.0.5" + acorn "^8.1.0" acorn-globals "^6.0.0" cssom "^0.4.4" - cssstyle "^2.2.0" + cssstyle "^2.3.0" data-urls "^2.0.0" - decimal.js "^10.2.0" + decimal.js "^10.2.1" domexception "^2.0.1" - escodegen "^1.14.1" + escodegen "^2.0.0" html-encoding-sniffer "^2.0.1" is-potential-custom-element-name "^1.0.0" nwsapi "^2.2.0" - parse5 "5.1.1" + parse5 "6.0.1" request "^2.88.2" - request-promise-native "^1.0.8" - saxes "^5.0.0" + request-promise-native "^1.0.9" + saxes "^5.0.1" symbol-tree "^3.2.4" - tough-cookie "^3.0.1" + tough-cookie "^4.0.0" w3c-hr-time "^1.0.2" w3c-xmlserializer "^2.0.0" webidl-conversions "^6.1.0" whatwg-encoding "^1.0.5" whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - ws "^7.2.3" + whatwg-url "^8.5.0" + ws "^7.4.4" xml-name-validator "^3.0.0" jsesc@^2.5.1: @@ -6006,65 +5889,65 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsii-diff@^1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.28.0.tgz#16f889559f3d2679154f93eae004704db1e6c62d" - integrity sha512-SJUzVY7sXg3esBeuvj3tQGzeRYEkpmrqbC1lIHd8VdXpPybYWU958z3hlJJkvaM1AomQpiMyXK6Ev+2XOp741g== +jsii-diff@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii-diff/-/jsii-diff-1.29.0.tgz#572bd3e0c9172fac3f1bf1cc4635501f57bbc8a0" + integrity sha512-Zc+h5C2XUGgVtT3qxerIDtPlvtjie45b5o5bZ6T/R+p0ClULrYmRl74+u1ztLqtOYcVqkhs6Qj11dgyZOCGzBA== dependencies: - "@jsii/spec" "^1.28.0" + "@jsii/spec" "^1.29.0" fs-extra "^9.1.0" - jsii-reflect "^1.28.0" + jsii-reflect "^1.29.0" log4js "^6.3.0" typescript "~3.9.9" yargs "^16.2.0" -jsii-pacmak@^1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.28.0.tgz#3d20c27a91266cf740a1ff229b29270785d2bcfc" - integrity sha512-QAW8rq7M9rA/QSXwaJKMVpttkNW/BJgE9GT6i9UahobQMkmp+zsXCJUENeRg2mndLqX0DDyxO1in/fuIeCeR3A== +jsii-pacmak@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii-pacmak/-/jsii-pacmak-1.29.0.tgz#12db86247f7350379d6a34d9a2aebec816c10152" + integrity sha512-wpVDrvh+hClB4Y68v/sYCcRnXlXoDwEUTC0X+uz9o5xUHs/WfuDglS5AAhq6g51INAQc0ed3anrkqmFcDK6QPw== dependencies: - "@jsii/spec" "^1.28.0" + "@jsii/spec" "^1.29.0" clone "^2.1.2" - codemaker "^1.28.0" + codemaker "^1.29.0" commonmark "^0.29.3" escape-string-regexp "^4.0.0" fs-extra "^9.1.0" - jsii-reflect "^1.28.0" - jsii-rosetta "^1.28.0" + jsii-reflect "^1.29.0" + jsii-rosetta "^1.29.0" semver "^7.3.5" spdx-license-list "^6.4.0" xmlbuilder "^15.1.1" yargs "^16.2.0" -jsii-reflect@^1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.28.0.tgz#d03276499702115ff0582f82ede7bd40f1a4b6b9" - integrity sha512-jFu9dUy5D0PrxVnaDilb50agbSr0wZRya6StwHyw8Wly3ruzS8uuSB1aWmEwN371m5ewDD4m9nPEQ9zMmKFvMQ== +jsii-reflect@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii-reflect/-/jsii-reflect-1.29.0.tgz#eaa80f383619586cddab1f296bb5a30c7157c3a0" + integrity sha512-r1XpKsnaMTaI0B2XXJ4rF1rbufqFDThASrArE+SyuuGeWTJxWQ4UtIzvXNVFLbZba0A5hX4K0JxiMIfaRFCEEg== dependencies: - "@jsii/spec" "^1.28.0" + "@jsii/spec" "^1.29.0" colors "^1.4.0" fs-extra "^9.1.0" - oo-ascii-tree "^1.28.0" + oo-ascii-tree "^1.29.0" yargs "^16.2.0" -jsii-rosetta@^1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.28.0.tgz#89625e817d4bf50fe51924177eb78bcb08908193" - integrity sha512-lttDhXiBuWaN0DwsWakD5o7GxyVP8yMCRvpmpXOqz1eK+MMlZp654R6o39M7RksXhhxipCNwfbIY3T7Y7N85qQ== +jsii-rosetta@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii-rosetta/-/jsii-rosetta-1.29.0.tgz#6363df806efd49ab09a0ff2062b7bf2cb289a141" + integrity sha512-WhTlFFm/xp2ictShT7XreBoqNpFj/U4MK4VyHyzYV1jS58uvJJMkwifMz/MOqciqRtWIAvGM3Ria4EB3VqmTfA== dependencies: - "@jsii/spec" "^1.28.0" + "@jsii/spec" "^1.29.0" commonmark "^0.29.3" fs-extra "^9.1.0" typescript "~3.9.9" xmldom "^0.5.0" yargs "^16.2.0" -jsii@^1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.28.0.tgz#c453f2a81d001dd2c3c3991e6e36d4bbb1d03f42" - integrity sha512-B6CbHi60fabeQZJYNea8wSUsrILJzN7ng+yx69GmMJ4C6NtCVt7Oc/CITfhY/cYTwdhN3FAJf01e5/v8qj6bUA== +jsii@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/jsii/-/jsii-1.29.0.tgz#1f34c29db9299ace0f361e6d72627d4478994396" + integrity sha512-7o1yE/si/nbGsNquSejwxaiPq0iDSTPfDENd7ZyO3xzGIROV8UZSs+VhGyys9t/VF4og8p9s2olkajEN60fzMw== dependencies: - "@jsii/spec" "^1.28.0" + "@jsii/spec" "^1.29.0" case "^1.6.3" colors "^1.4.0" deep-equal "^2.0.5" @@ -6199,9 +6082,9 @@ jszip@*, jszip@^3.6.0: set-immediate-shim "~1.0.1" just-extend@^4.0.2: - version "4.1.1" - resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.1.tgz#158f1fdb01f128c411dc8b286a7b4837b3545282" - integrity sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA== + version "4.2.1" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" + integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" @@ -6315,25 +6198,25 @@ levn@~0.3.0: type-check "~0.3.2" libnpmaccess@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.1.tgz#17e842e03bef759854adf6eb6c2ede32e782639f" - integrity sha512-ZiAgvfUbvmkHoMTzdwmNWCrQRsDkOC+aM5BDfO0C9aOSwF3R1LdFDBD+Rer1KWtsoQYO35nXgmMR7OUHpDRxyA== + version "4.0.2" + resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.2.tgz#781832fb7ccb867b26343a75a85ad9c43e50406e" + integrity sha512-avXtJibZuGap0/qADDYqb9zdpgzVu/yG5+tl2sTRa7MCkDNv2ZlGwCYI0r6/+tmqXPj0iB9fKexHz426vB326w== dependencies: aproba "^2.0.0" minipass "^3.1.1" - npm-package-arg "^8.0.0" - npm-registry-fetch "^9.0.0" + npm-package-arg "^8.1.2" + npm-registry-fetch "^10.0.0" libnpmpublish@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.0.tgz#ad6413914e0dfd78df868ce14ba3d3a4cc8b385b" - integrity sha512-2RwYXRfZAB1x/9udKpZmqEzSqNd7ouBRU52jyG14/xG8EF+O9A62d7/XVR3iABEQHf1iYhkm0Oq9iXjrL3tsXA== + version "4.0.1" + resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.1.tgz#08ca2cbb5d7f6be1ce4f3f9c49b3822682bcf166" + integrity sha512-hZCrZ8v4G9YH3DxpIyBdob25ijD5v5LNzRbwsej4pPDopjdcLLj1Widl+BUeFa7D0ble1JYL4F3owjLJqiA8yA== dependencies: - normalize-package-data "^3.0.0" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" + normalize-package-data "^3.0.2" + npm-package-arg "^8.1.2" + npm-registry-fetch "^10.0.0" semver "^7.1.3" - ssri "^8.0.0" + ssri "^8.0.1" lie@~3.3.0: version "3.3.0" @@ -6480,11 +6363,6 @@ lodash.set@^4.3.2: resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - lodash.template@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" @@ -6510,7 +6388,7 @@ lodash.union@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= -lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: +lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6628,9 +6506,9 @@ map-obj@^1.0.0, map-obj@^1.0.1: integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= map-obj@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.0.tgz#0e8bc823e2aaca8a0942567d12ed14f389eec153" - integrity sha512-NAq0fCmZYGz9UFEQyndp7sisrow4GroyGeKluyKC/chuITZsPyOyC1UJZPJlVFImhXdROIP5xqouRLThT3BbpQ== + version "4.2.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" + integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== map-visit@^1.0.0: version "1.0.0" @@ -6771,24 +6649,24 @@ micromatch@^3.1.4: to-regex "^3.0.2" micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== dependencies: braces "^3.0.1" - picomatch "^2.0.5" + picomatch "^2.2.3" -mime-db@1.46.0: - version "1.46.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee" - integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ== +mime-db@1.47.0: + version "1.47.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c" + integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw== mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.29" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2" - integrity sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ== + version "2.1.30" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d" + integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg== dependencies: - mime-db "1.46.0" + mime-db "1.47.0" mimic-fn@^2.1.0: version "2.1.0" @@ -6927,10 +6805,10 @@ mkdirp@^0.5.0, mkdirp@^0.5.1: dependencies: minimist "^1.2.5" -mock-fs@^4.13.0: - version "4.13.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.13.0.tgz#31c02263673ec3789f90eb7b6963676aa407a598" - integrity sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA== +mock-fs@^4.14.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" + integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== mockery@^2.1.0: version "2.1.0" @@ -7011,9 +6889,9 @@ nested-error-stacks@^2.0.0: integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== netmask@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.1.tgz#5a5cbdcbb7b6de650870e15e83d3e9553a414cf4" - integrity sha512-gB8eG6ubxz67c7O2gaGiyWdRUIbH61q7anjgueDqCC9kvIs/b4CTtCMaQKeJbv1/Y7FT19I4zKwYmjnjInRQsg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== nice-try@^1.0.4: version "1.0.5" @@ -7108,7 +6986,7 @@ node-preload@^0.2.1: dependencies: process-on-spawn "^1.0.0" -node-releases@^1.1.70: +node-releases@^1.1.71: version "1.1.71" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== @@ -7146,14 +7024,14 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.1.tgz#98dc56dfe6755d99b1c53f046e1e3d2dde55a1c7" - integrity sha512-D/ttLdxo71msR4FF3VgSwK4blHfE3/vGByz1NCeE7/Dh8reQOKNJJjk5L10mLq9jxa+ZHzT1/HLgxljzbXE7Fw== +normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.2.tgz#cae5c410ae2434f9a6c1baa65d5bc3b9366c8699" + integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg== dependencies: - hosted-git-info "^4.0.0" - resolve "^1.17.0" - semver "^7.3.2" + hosted-git-info "^4.0.1" + resolve "^1.20.0" + semver "^7.3.4" validate-npm-package-license "^3.0.1" normalize-path@^2.1.1: @@ -7173,10 +7051,10 @@ normalize-url@^3.3.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== -npm-bundled@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" - integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== +npm-bundled@^1.1.1, npm-bundled@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== dependencies: npm-normalize-package-bin "^1.0.1" @@ -7216,16 +7094,16 @@ npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-pack validate-npm-package-name "^3.0.0" npm-packlist@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.1.4.tgz#40e96b2b43787d0546a574542d01e066640d09da" - integrity sha512-Qzg2pvXC9U4I4fLnUrBmcIT4x0woLtUgxUi9eC+Zrcv1Xx5eamytGAfbDWQ67j7xOcQ2VW1I3su9smVTIdu7Hw== + version "2.2.2" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" + integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg== dependencies: glob "^7.1.6" ignore-walk "^3.0.3" npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -npm-pick-manifest@^6.0.0: +npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== @@ -7235,6 +7113,19 @@ npm-pick-manifest@^6.0.0: npm-package-arg "^8.1.2" semver "^7.3.4" +npm-registry-fetch@^10.0.0: + version "10.1.1" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-10.1.1.tgz#97bc7a0fca5e8f76cc5162185b8de8caa8bea639" + integrity sha512-F6a3l+ffCQ7hvvN16YG5bpm1rPZntCg66PLHDQ1apWJPOCUVHoKnL2w5fqEaTVhp42dmossTyXeR7hTGirfXrg== + dependencies: + lru-cache "^6.0.0" + make-fetch-happen "^8.0.9" + minipass "^3.1.3" + minipass-fetch "^1.3.0" + minipass-json-stream "^1.0.1" + minizlib "^2.0.0" + npm-package-arg "^8.0.0" + npm-registry-fetch@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" @@ -7278,11 +7169,6 @@ null-check@^1.0.0: resolved "https://registry.yarnpkg.com/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.yarnpkg.com/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.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" @@ -7372,9 +7258,9 @@ object-copy@^0.1.0: kind-of "^3.0.3" object-inspect@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" - integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== + version "1.10.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" + integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== object-is@^1.1.4: version "1.1.5" @@ -7446,10 +7332,10 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -oo-ascii-tree@^1.28.0: - version "1.28.0" - resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.28.0.tgz#2bafc084f7725b118b5a8511944a8dd4ebef14df" - integrity sha512-lCeBgtQutG2+K7BOJDurYNfCepvckj7jWtq2VVP1kseLry/VbLzE/oLiXEeK6iWUXJbBE2IzmxwGuUwee293yw== +oo-ascii-tree@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/oo-ascii-tree/-/oo-ascii-tree-1.29.0.tgz#101db364fad798656bec7add53cd9ab1a4f2bf4e" + integrity sha512-DUwUL3Yc3lS2znWBlOi5eEU4pKoGGK2IaB/S7XygSBzmSS2jJE6+waAip17FNeNXfC4aXClr95HxZXamCLtYqQ== open@^7.4.2: version "7.4.2" @@ -7683,9 +7569,9 @@ package-hash@^4.0.0: release-zalgo "^1.0.0" pacote@^11.2.6: - version "11.3.0" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.0.tgz#b2e16791a39cd4d9fb9fc1ec240cefe7ea518e6f" - integrity sha512-cygprcGpEVqvDzpuPMkGVXW/ooc2ibpoosuJ4YHcUXozDs9VJP7Vha+41pYppG2MVNis4t1BB8IygIBh7vVr2Q== + version "11.3.3" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.3.tgz#d7d6091464f77c09691699df2ded13ab906b3e68" + integrity sha512-GQxBX+UcVZrrJRYMK2HoG+gPeSUX/rQhnbPkkGrCYa4n2F/bgClFPaMm0nsdnYrxnmUy85uMHoFXZ0jTD0drew== dependencies: "@npmcli/git" "^2.0.1" "@npmcli/installed-package-contents" "^1.0.6" @@ -7700,7 +7586,7 @@ pacote@^11.2.6: npm-package-arg "^8.0.1" npm-packlist "^2.1.4" npm-pick-manifest "^6.0.0" - npm-registry-fetch "^9.0.0" + npm-registry-fetch "^10.0.0" promise-retry "^2.0.1" read-package-json-fast "^2.0.1" rimraf "^3.0.2" @@ -7769,10 +7655,10 @@ parse-url@^5.0.0: parse-path "^4.0.0" protocols "^1.4.0" -parse5@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== pascalcase@^0.1.1: version "0.1.1" @@ -7875,10 +7761,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" + integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== pify@^2.0.0, pify@^2.3.0: version "2.3.0" @@ -8008,9 +7894,9 @@ promptly@^3.2.0: read "^1.0.4" prompts@^2.0.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" - integrity sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ== + version "2.4.1" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" + integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ== dependencies: kleur "^3.0.3" sisteransi "^1.0.5" @@ -8070,7 +7956,7 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= -psl@^1.1.28: +psl@^1.1.28, psl@^1.1.33: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== @@ -8104,9 +7990,11 @@ q@^1.5.1: integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= qs@^6.9.4: - version "6.9.6" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" - integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + version "6.10.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + dependencies: + side-channel "^1.0.4" qs@~6.5.2: version "6.5.2" @@ -8129,9 +8017,9 @@ querystring@0.2.0: integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= queue-microtask@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.2.tgz#abf64491e6ecf0f38a6502403d4cda04f372dfd3" - integrity sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg== + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== quick-lru@^4.0.1: version "4.0.1" @@ -8159,9 +8047,9 @@ rc@~1.2.8: strip-json-comments "~2.0.1" react-is@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" - integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== read-cmd-shim@^2.0.0: version "2.0.0" @@ -8186,7 +8074,7 @@ read-package-json@^2.0.0: normalize-package-data "^2.0.0" npm-normalize-package-bin "^1.0.0" -read-package-json@^3.0.0: +read-package-json@^3.0.0, read-package-json@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" integrity sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng== @@ -8396,9 +8284,9 @@ remove-trailing-separator@^1.0.1: integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== repeat-string@^1.6.1: version "1.6.1" @@ -8419,7 +8307,7 @@ request-promise-core@1.1.4: dependencies: lodash "^4.17.19" -request-promise-native@^1.0.8: +request-promise-native@^1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== @@ -8491,7 +8379,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -8559,9 +8447,9 @@ run-parallel@^1.1.9: queue-microtask "^1.2.2" rxjs@^6.6.0: - version "6.6.6" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70" - integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg== + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" @@ -8612,7 +8500,7 @@ sax@>=0.6.0, sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -saxes@^5.0.0: +saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== @@ -8631,10 +8519,10 @@ semver-intersect@^1.4.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.x, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== +semver@7.x, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" @@ -8643,13 +8531,6 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -8720,7 +8601,7 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== -side-channel@^1.0.3: +side-channel@^1.0.3, side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== @@ -8734,7 +8615,7 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -sinon@^9.0.1, sinon@^9.0.2, sinon@^9.2.4: +sinon@^9.0.1, sinon@^9.2.4: version "9.2.4" resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b" integrity sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg== @@ -8820,9 +8701,9 @@ socks-proxy-agent@5, socks-proxy-agent@^5.0.0: socks "^2.3.3" socks@^2.3.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.0.tgz#6b984928461d39871b3666754b9000ecf39dfac2" - integrity sha512-mNmr9owlinMplev0Wd7UHFlqI4ofnBnNzFuzrm63PPaHgbkqCFe4T5LzwKmtQ/f2tX0NTpcdVLyD/FHxFBstYw== + version "2.6.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" + integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== dependencies: ip "^1.1.5" smart-buffer "^4.1.0" @@ -8998,9 +8879,9 @@ ssri@^8.0.0, ssri@^8.0.1: minipass "^3.1.1" stack-utils@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.4.tgz#4b600971dcfc6aed0cbdf2a8268177cc916c87c8" - integrity sha512-IPDJfugEGbfizBwBZRZ3xpccMdRyP5lqsBWXGQWimVjua/ccLCeMOAVjlc1R7LxFjo5sEDhyNIXd8mo/AiDS9w== + version "1.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.5.tgz#a19b0b01947e0029c8e451d5d61a498f5bb1471b" + integrity sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ== dependencies: escape-string-regexp "^2.0.0" @@ -9011,10 +8892,10 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" -standard-version@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.2.0.tgz#d4e64b201ec1abb8a677b265d8755e5e8b9e33a3" - integrity sha512-utJcqjk/wR4sePSwDoRcc5CzJ6S+kec5Hd0+1TJI+j1TRYuuptweAnEUdkkjGf2vYoGab2ezefyVtW065HZ1Uw== +standard-version@^9.3.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.3.0.tgz#2e6ff439aa49b2ea8952262f30ae6b70c02467d3" + integrity sha512-cYxxKXhYfI3S9+CA84HmrJa9B88H56V5FQ302iFF2TNwJukJCNoU8FgWt+11YtwKFXRkQQFpepC2QOF7aDq2Ow== dependencies: chalk "^2.4.2" conventional-changelog "3.1.24" @@ -9072,7 +8953,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.2: +string-width@*, string-width@^1.0.1, "string-width@^1.0.2 || 2", string-width@^3.0.0, string-width@^3.1.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== @@ -9081,32 +8962,6 @@ string-width@*, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/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.yarnpkg.com/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-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - string.prototype.repeat@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz#aba36de08dcee6a5a337d49b2ea1da1b28fc0ecf" @@ -9159,14 +9014,7 @@ 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.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: +strip-ansi@^5.0.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -9262,9 +9110,9 @@ supports-color@^7.0.0, supports-color@^7.1.0: has-flag "^4.0.0" supports-hyperlinks@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" - integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" @@ -9274,45 +9122,17 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@^6.0.4: - version "6.0.7" - resolved "https://registry.yarnpkg.com/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" - integrity sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g== - dependencies: - ajv "^7.0.2" - lodash "^4.17.20" - slice-ansi "^4.0.0" - string-width "^4.2.0" - -table@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/table/-/table-6.1.0.tgz#676a0cfb206008b59e783fcd94ef8ba7d67d966c" - integrity sha512-T4G5KMmqIk6X87gLKWyU5exPpTjLjY5KyrFWaIjv3SvgaIUGXV7UEzGEnZJdTA38/yUS6f9PlKezQ0bYXG3iIQ== +table@*, table@^6.0.4, table@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.7.0.tgz#26274751f0ee099c547f6cb91d3eff0d61d155b2" + integrity sha512-SAM+5p6V99gYiiy2gT5ArdzgM1dLDed0nkrWmG6Fry/bUS/m9x83BwpJUOf1Qj/x2qJd+thL6IkIx7qPGRxqBw== dependencies: ajv "^8.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" lodash.clonedeep "^4.5.0" - lodash.flatten "^4.4.0" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.0" - -table@^6.3.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/table/-/table-6.3.2.tgz#afa86bee5cfe305f9328f89bb3e5454132cdea28" - integrity sha512-I9/Ca6Huf2oxFag7crD0DhA+arIdfLtWunSn0NIXSzjtUlDgIBGVZY7SsMkNPNT3Psd/z4gza0nuEpmra9eRbg== - dependencies: - ajv "^8.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - lodash.clonedeep "^4.5.0" - lodash.flatten "^4.4.0" lodash.truncate "^4.4.2" slice-ansi "^4.0.0" string-width "^4.2.0" + strip-ansi "^6.0.0" tap-mocha-reporter@^3.0.9, tap-mocha-reporter@^5.0.1: version "5.0.1" @@ -9587,14 +9407,14 @@ tough-cookie@^2.3.3, tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" -tough-cookie@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" - integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== dependencies: - ip-regex "^2.1.0" - psl "^1.1.28" + psl "^1.1.33" punycode "^2.1.1" + universalify "^0.1.2" tr46@^2.0.2: version "2.0.2" @@ -9628,10 +9448,10 @@ trivial-deferred@^1.0.1: resolved "https://registry.yarnpkg.com/trivial-deferred/-/trivial-deferred-1.0.1.tgz#376d4d29d951d6368a6f7a0ae85c2f4d5e0658f3" integrity sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM= -ts-jest@^26.5.4: - version "26.5.4" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.4.tgz#207f4c114812a9c6d5746dd4d1cdf899eafc9686" - integrity sha512-I5Qsddo+VTm94SukBJ4cPimOoFZsYTeElR2xy6H2TOVs+NsvgYglW8KuQgKoApOKuaU/Ix/vrF9ebFZlb5D2Pg== +ts-jest@^26.5.6: + version "26.5.6" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" + integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== dependencies: bs-logger "0.x" buffer-from "1.x" @@ -9644,10 +9464,10 @@ ts-jest@^26.5.4: semver "7.x" yargs-parser "20.x" -ts-mock-imports@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/ts-mock-imports/-/ts-mock-imports-1.3.3.tgz#7865888382806aa8f09412ab582a8e06f2bd1b6d" - integrity sha512-zCAcb89Y+f3Bhw5VaHrHMh5tiuwAQEl5D3e0r5ELCdLl9EnZpb8Oeei/S60Qf4LORIfmJEXb3TpR5kxtL6j2cg== +ts-mock-imports@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ts-mock-imports/-/ts-mock-imports-1.3.4.tgz#09f23f2ad24258fd2e6e2723b4ad6172429fc093" + integrity sha512-sfLou3sXExgkq/ia0XKfRLtnXwMBIqfpSoPRT5vQRt8fqSlDPy8PaPz5N6lfkebnb0qW2qM4cKOURYP1L/+yuA== ts-node@^8.0.2: version "8.10.2" @@ -9693,9 +9513,9 @@ tslib@^1.8.1, tslib@^1.9.0: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" - integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + version "2.2.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" + integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== tsutils@^3.17.1: version "3.21.0" @@ -9735,11 +9555,6 @@ type-detect@4.0.8, type-detect@^4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" - integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== - type-fest@^0.18.0: version "0.18.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" @@ -9750,6 +9565,11 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" @@ -9796,9 +9616,9 @@ typescript@^3.3.3, typescript@~3.9.9: integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w== typescript@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" - integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw== + version "4.2.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" + integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== typescript@~3.8.3: version "3.8.3" @@ -9811,9 +9631,9 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== uglify-js@^3.1.4: - version "3.13.1" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.1.tgz#2749d4b8b5b7d67460b4a418023ff73c3fefa60a" - integrity sha512-EWhx3fHy3M9JbaeTnO+rEqzCe1wtyQClv6q3YWq0voOj4E+bMZBErVS1GAHPDiRGONYq34M1/d8KuQMgvi6Gjw== + version "3.13.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.5.tgz#5d71d6dbba64cf441f32929b1efce7365bb4f113" + integrity sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw== uid-number@0.0.6: version "0.0.6" @@ -9826,14 +9646,14 @@ umask@^1.1.0: integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= unbox-primitive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.0.tgz#eeacbc4affa28e9b3d36b5eaeccc50b3251b1d3f" - integrity sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA== + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== dependencies: function-bind "^1.1.1" - has-bigints "^1.0.0" - has-symbols "^1.0.0" - which-boxed-primitive "^1.0.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" unicode-length@^2.0.2: version "2.0.2" @@ -9872,7 +9692,7 @@ universal-user-agent@^6.0.0: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== -universalify@^0.1.0: +universalify@^0.1.0, universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== @@ -9963,9 +9783,9 @@ v8-compile-cache@^2.0.3: integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== v8-to-istanbul@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz#5b95cef45c0f83217ec79f8fc7ee1c8b486aee07" - integrity sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g== + version "7.1.2" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" + integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" @@ -10050,16 +9870,16 @@ whatwg-mimetype@^2.3.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== -whatwg-url@^8.0.0, whatwg-url@^8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.4.0.tgz#50fb9615b05469591d2b2bd6dfaed2942ed72837" - integrity sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw== +whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.5.0.tgz#7752b8464fc0903fec89aa9846fc9efe07351fd3" + integrity sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg== dependencies: - lodash.sortby "^4.7.0" + lodash "^4.7.0" tr46 "^2.0.2" webidl-conversions "^6.1.0" -which-boxed-primitive@^1.0.1: +which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== @@ -10213,10 +10033,10 @@ write-pkg@^4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@^7.2.3: - version "7.4.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59" - integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw== +ws@^7.4.4: + version "7.4.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1" + integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g== xml-js@^1.6.11: version "1.6.11" @@ -10274,14 +10094,14 @@ xtend@~4.0.1: integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== y18n@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" - integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ== + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== y18n@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" - integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yallist@^2.1.2: version "2.1.2"