konokenj.cdk-api-mcp-server 0.44.0__py3-none-any.whl → 0.46.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of konokenj.cdk-api-mcp-server might be problematic. Click here for more details.

Files changed (30) hide show
  1. cdk_api_mcp_server/__about__.py +1 -1
  2. cdk_api_mcp_server/resources/aws-cdk/constructs/@aws-cdk/custom-resource-handlers/README.md +15 -78
  3. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-cloudfront-origins/README.md +36 -0
  4. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-cloudfront-origins/integ.origin-response-completion-timeout.ts +50 -0
  5. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-codedeploy/integ.deployment-config.ts +4 -15
  6. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-codedeploy/integ.deployment-group.ts +218 -40
  7. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs/integ.availability-zone-rebalancing.ts +14 -4
  8. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs/integ.enable-execute-command.ts +35 -29
  9. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs/integ.exec-command.ts +16 -22
  10. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs/integ.lb-awsvpc-nw.ts +26 -16
  11. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs/integ.pseudo-terminal.ts +18 -8
  12. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-elasticloadbalancingv2/README.md +21 -0
  13. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-elasticloadbalancingv2/integ.alb-target-group-attributes.ts +45 -0
  14. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-elasticloadbalancingv2/integ.nlb-target-group-attributes.ts +45 -0
  15. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-events/README.md +18 -1
  16. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-events/integ.eventbus.ts +13 -3
  17. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-route53/README.md +24 -0
  18. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-route53/integ.route53.ts +51 -1
  19. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-route53-targets/integ.cloudfront-alias-target.ts +16 -1
  20. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/README.md +53 -0
  21. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/integ.emr-create-cluster-with-ebs.ts +126 -0
  22. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/integ.invoke-jsonata.ts +80 -87
  23. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/integ.invoke.ts +69 -87
  24. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/integ.start-job-run.ts +43 -96
  25. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/cloudformation-include/integ.novalue-nonstring.ts +25 -0
  26. {konokenj_cdk_api_mcp_server-0.44.0.dist-info → konokenj_cdk_api_mcp_server-0.46.0.dist-info}/METADATA +2 -2
  27. {konokenj_cdk_api_mcp_server-0.44.0.dist-info → konokenj_cdk_api_mcp_server-0.46.0.dist-info}/RECORD +30 -25
  28. {konokenj_cdk_api_mcp_server-0.44.0.dist-info → konokenj_cdk_api_mcp_server-0.46.0.dist-info}/WHEEL +0 -0
  29. {konokenj_cdk_api_mcp_server-0.44.0.dist-info → konokenj_cdk_api_mcp_server-0.46.0.dist-info}/entry_points.txt +0 -0
  30. {konokenj_cdk_api_mcp_server-0.44.0.dist-info → konokenj_cdk_api_mcp_server-0.46.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2025-present Kenji Kono <konoken@amazon.co.jp>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
- __version__ = "0.44.0"
4
+ __version__ = "0.46.0"
@@ -1,83 +1,20 @@
1
- # CDK Handler Framework
1
+ # Type definitions copied from 'aws-cdk-lib'
2
2
 
3
- The CDK handler framework is an internal framework used to code generate constructs that extend a lambda `Function`, lambda `SingletonFunction`, or core `CustomResourceProvider` construct and prohibit the user from directly configuring the `handler`, `runtime`, `code`, and `codeDirectory` properties. In doing this, we are able to establish best practices, runtime enforcement, and consistency across all handlers we build and vend within the aws-cdk.
3
+ `aws-cdk-lib` depends on this package; but this package depends on some
4
+ types defined in `aws-cdk-lib`.
4
5
 
5
- ## CDK Handler Framework Concepts
6
+ This cyclic dependency leads to a non-executable build graph. In order to
7
+ break the cycle, we're just copying some types over from `aws-cdk-lib`.
6
8
 
7
- This framework allows for the creation of three component types:
8
- 1. `ComponentType.FUNCTION` - This is a wrapper around the lambda `Function` construct. It offers the same behavior and performance as a lambda `Function`, but it restricts the consumer from configuring the `handler`, `runtime`, and `code` properties.
9
- 2. `ComponentType.SINGLETON_FUNCTION` - This is a wrapper around the lambda `SingletonFunction` construct. It offers the same behavior and performance as a lambda `SingletonFunction`, but it restricts the consumer from configuring the `handler`, `runtime`, and `code` properties.
10
- 3. `ComponentType.CUSTOM_RESOURCE_PROVIDER` - This is a wrapper around the core `CustomResourceProvider` construct. It offers the same behavior and performance as a `CustomResourceProvider` and can be instantiated via the `getOrCreate` or `getOrCreateProvider` methods. This component restricts the consumer from configuring the `runtime` and `codeDirectory` properties.
9
+ I readily admit this is not a great long-term solution, but those types have
10
+ been stable for years and are unlikely to change. The correct solution would
11
+ probably be to externalize them into a separate package, but even the most
12
+ simple solution of that accord would require bundling the types into
13
+ `aws-cdk-lib` with `bundledDependencies` and that requires us writing a
14
+ replacement for `npm pack`, because by default NPM will refuse to bundle
15
+ `bundledDependencies` that have been symlinked into a local workspace (in fact,
16
+ it will silently ignore them).
11
17
 
12
- Code generating one of these three component types requires adding the component properties to the [config](./config.ts) file by providing `ComponentProps`. The `ComponentProps` are responsible for code generating the specified `ComponentType` with the `handler`, `runtime`, `code`, and `codeDirectory` properties set internally. `ComponentProps` includes the following properties:
13
- - `type` - the framework component type to generate.
14
- - `sourceCode` - the source code that will be excuted by the framework component.
15
- - `runtime` - the runtime that is compatible with the framework component's source code. This is an optional property with a default node runtime that will be the latest available node runtime in the `Stack` deployment region. In general, you should not configure this property unless a `runtime` override is absolutely necessary.
16
- - `handler` - the name of the method with the source code that the framework component will call. This is an optional property and the default is `index.handler`.
17
- - `minifyAndBundle` - whether the source code should be minified and bundled. This an optional property and the default is `true`. This should only be set to `false` for python files or for typescript/javascript files with a require import.
18
+ We can build our own replacement for `npm pack`, or we can do a little
19
+ copy/paste. I'm opting for the latter.
18
20
 
19
- The [config](./config.ts) file is structured with the top level mapping to an aws-cdk module, i.e., aws-s3, aws-dynamodb, etc. Each service can contain one or more component modules. Component modules are containers for handler framework components and will be rendered as a code generated file. Each component module can contain one or more `ComponentProps` objects. The following example shows a more structural breakdown of how the [config](./config.ts) file is configured:
20
-
21
- ```ts
22
- const config = {
23
- 'aws-s3': { // the aws-cdk-lib module
24
- 'replica-provider': [ // the component module
25
- // handler framework component defined as a `ComponentProps` object
26
- {
27
- // the handler framework component type
28
- type: ComponentType.FUNCTION,
29
- // the source code that the component will use
30
- sourceCode: path.resolve(__dirname, '..', 'aws-dynamodb', 'replica-handler', 'index.ts'),
31
- // the handler in the source code that the component will execute
32
- handler: 'index.onEventHandler',
33
- },
34
- ],
35
- },
36
- 'aws-stepfunctions-tasks': {
37
- // contains multiple component modules
38
- 'eval-nodejs-provider': [
39
- {
40
- type: ComponentType.SINGLETON_FUNCTION,
41
- sourceCode: path.resolve(__dirname, '..', 'aws-stepfunctions-tasks', 'eval-nodejs-handler', 'index.ts'),
42
- },
43
- ],
44
- 'role-policy-provider': [
45
- {
46
- type: ComponentType.SINGLETON_FUNCTION,
47
- sourceCode: path.resolve(__dirname, '..', 'aws-stepfunctions-tasks', 'role-policy-handler', 'index.py'),
48
- runtime: Runtime.PYTHON_3_9,
49
- // prevent minify and bundle since the source code is a python file
50
- minifyAndBundle: false,
51
- },
52
- ],
53
- },
54
- };
55
- ```
56
-
57
- Code generation for the component modules is triggered when this package - `@aws-cdk/custom-resource-handlers` - is built. Importantly, this framework is also responsible for minifying and bundling the custom resource providers' source code and dependencies. A flag named `minifyAndBundle` can be configured as part of the `ComponentProps` to prevent minifying and bundling the source code for a specific provider. This flag is only needed for python files or for typescript/javascript files containing require imports.
58
-
59
- Once built, all generated code and bundled source code will be written to `@aws-cdk/custom-resource-handlers/dist`. The top level field in the [config](./config.ts) file defining individual aws-cdk modules will be used to create specific directories within `@aws-cdk/custom-resource-handlers/dist` and each component module will be a separate code generated file within these directories named `<component-module>.generated.ts`. As an example, the sample [config](./config.ts) file above would create the following file structure:
60
-
61
- |--- @aws-cdk
62
- | |--- custom-resource-handlers
63
- | | |--- dist
64
- | | | |--- aws-s3
65
- | | | | |--- replica-handler
66
- | | | | | |--- index.js
67
- | | | | |--- replica-provider.generated.ts
68
- | | | |--- aws-stepfunctions-tasks
69
- | | | | |--- eval-nodejs-handler
70
- | | | | | |--- index.js
71
- | | | | |--- role-policy-handler
72
- | | | | | |--- index.py
73
- | | | | |--- eval-nodejs-provider.generated.ts
74
- | | | | |--- role-policy-provider.generated.ts
75
-
76
- The code generated handler framework components are consumable from `aws-cdk-lib/custom-resource-handlers/dist` once `aws-cdk-lib` is built. The file structure of `aws-cdk-lib/custom-resource-handlers/dist` will have the same structure as `@aws-cdk/custom-resource-handlers/dist` with the exception of `core`. To prevent circular dependencies, all handler framework components defined in `core`and any associated source code will be consumable from `aws-cdk-lib/core/dist/core`.
77
-
78
- ## Creating a Handler Framework Component
79
-
80
- Creating a new handler framework component involves three steps:
81
- 1. Add the source code to `@aws-cdk/custom-resource-handlers/lib/<aws-cdk-lib-module>`
82
- 2. Update the [config](./config.ts) file by specifying all required `ComponentProps`.
83
- 3. At this point you can directly build `@aws-cdk/custom-resource-handlers` with `yarn build` to view the generated component in `@aws-cdk/custom-resource-handlers/dist`. Alternatively, you can build `aws-cdk-lib` with `npx lerna run build --scope=aws-cdk-lib --skip-nx-cache` to make the generated component available for use within `aws-cdk-lib`
@@ -577,6 +577,7 @@ const origin = new origins.LoadBalancerV2Origin(loadBalancer, {
577
577
  connectionAttempts: 3,
578
578
  connectionTimeout: Duration.seconds(5),
579
579
  readTimeout: Duration.seconds(45),
580
+ responseCompletionTimeout: Duration.seconds(120),
580
581
  keepaliveTimeout: Duration.seconds(45),
581
582
  protocolPolicy: cloudfront.OriginProtocolPolicy.MATCH_VIEWER,
582
583
  });
@@ -596,6 +597,22 @@ new cloudfront.Distribution(this, 'myDist', {
596
597
  });
597
598
  ```
598
599
 
600
+ The origin can be customized with timeout settings to handle different response scenarios:
601
+
602
+ ```ts
603
+ new cloudfront.Distribution(this, 'Distribution', {
604
+ defaultBehavior: {
605
+ origin: new origins.HttpOrigin('api.example.com', {
606
+ readTimeout: Duration.seconds(60),
607
+ responseCompletionTimeout: Duration.seconds(120),
608
+ keepaliveTimeout: Duration.seconds(45),
609
+ }),
610
+ },
611
+ });
612
+ ```
613
+
614
+ The `responseCompletionTimeout` property specifies the time that a request from CloudFront to the origin can stay open and wait for a response. If the complete response isn't received from the origin by this time, CloudFront ends the connection. Valid values are 1-3600 seconds, and if set, the value must be equal to or greater than the `readTimeout` value.
615
+
599
616
  See the documentation of `aws-cdk-lib/aws-cloudfront` for more information.
600
617
 
601
618
  ## VPC origins
@@ -801,6 +818,25 @@ new cloudfront.Distribution(this, 'Distribution', {
801
818
  });
802
819
  ```
803
820
 
821
+ You can also configure timeout settings for Lambda Function URL origins:
822
+
823
+ ```ts
824
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
825
+
826
+ declare const fn: lambda.Function;
827
+ const fnUrl = fn.addFunctionUrl({ authType: lambda.FunctionUrlAuthType.NONE });
828
+
829
+ new cloudfront.Distribution(this, 'Distribution', {
830
+ defaultBehavior: {
831
+ origin: new origins.FunctionUrlOrigin(fnUrl, {
832
+ readTimeout: Duration.seconds(30),
833
+ responseCompletionTimeout: Duration.seconds(90),
834
+ keepaliveTimeout: Duration.seconds(45),
835
+ }),
836
+ },
837
+ });
838
+ ```
839
+
804
840
  ### Lambda Function URL with Origin Access Control (OAC)
805
841
  You can configure the Lambda Function URL with Origin Access Control (OAC) for enhanced security. When using OAC with Signing SIGV4_ALWAYS, it is recommended to set the Lambda Function URL authType to AWS_IAM to ensure proper authorization.
806
842
 
@@ -0,0 +1,50 @@
1
+ import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
2
+ import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
3
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
4
+ import * as cdk from 'aws-cdk-lib';
5
+ import { IntegTest } from '@aws-cdk/integ-tests-alpha';
6
+
7
+ const app = new cdk.App();
8
+ const stack = new cdk.Stack(app, 'integ-cloudfront-response-completion-timeout');
9
+
10
+ const httpOrigin = new origins.HttpOrigin('example.com', {
11
+ responseCompletionTimeout: cdk.Duration.seconds(120),
12
+ readTimeout: cdk.Duration.seconds(60),
13
+ });
14
+
15
+ const fn = new lambda.Function(stack, 'Function', {
16
+ runtime: lambda.Runtime.NODEJS_18_X,
17
+ handler: 'index.handler',
18
+ code: lambda.Code.fromInline('exports.handler = async () => ({ statusCode: 200, body: "Hello from Lambda!" });'),
19
+ });
20
+
21
+ const fnUrl = fn.addFunctionUrl({
22
+ authType: lambda.FunctionUrlAuthType.NONE,
23
+ });
24
+
25
+ const functionUrlOrigin = new origins.FunctionUrlOrigin(fnUrl, {
26
+ responseCompletionTimeout: cdk.Duration.seconds(90),
27
+ readTimeout: cdk.Duration.seconds(30),
28
+ });
29
+
30
+ const httpOriginNoReadTimeout = new origins.HttpOrigin('api.example.com', {
31
+ responseCompletionTimeout: cdk.Duration.seconds(300),
32
+ });
33
+
34
+ new cloudfront.Distribution(stack, 'Distribution', {
35
+ defaultBehavior: {
36
+ origin: httpOrigin,
37
+ },
38
+ additionalBehaviors: {
39
+ '/api/*': {
40
+ origin: functionUrlOrigin,
41
+ },
42
+ '/files/*': {
43
+ origin: httpOriginNoReadTimeout,
44
+ },
45
+ },
46
+ });
47
+
48
+ new IntegTest(app, 'CloudFrontResponseCompletionTimeoutTest', {
49
+ testCases: [stack],
50
+ });
@@ -2,28 +2,17 @@ import * as cdk from 'aws-cdk-lib';
2
2
  import * as integ from '@aws-cdk/integ-tests-alpha';
3
3
  import * as codedeploy from 'aws-cdk-lib/aws-codedeploy';
4
4
 
5
- const app = new cdk.App({
6
- postCliContext: {
7
- '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
8
- },
9
- });
10
- const stack = new cdk.Stack(app, 'aws-cdk-codedeploy-lambda-config');
5
+ const app = new cdk.App();
6
+ const stack = new cdk.Stack(app, 'aws-cdk-codedeploy-ecs-config');
11
7
 
12
- new codedeploy.LambdaDeploymentConfig(stack, 'LinearConfig', {
8
+ new codedeploy.EcsDeploymentConfig(stack, 'LinearConfig', {
13
9
  trafficRouting: codedeploy.TrafficRouting.timeBasedLinear({
14
10
  interval: cdk.Duration.minutes(1),
15
11
  percentage: 5,
16
12
  }),
17
13
  });
18
14
 
19
- new codedeploy.CustomLambdaDeploymentConfig(stack, 'CustomConfig', {
20
- interval: cdk.Duration.minutes(1),
21
- percentage: 5,
22
- type: cdk.aws_codedeploy.CustomLambdaDeploymentConfigType.LINEAR,
23
- deploymentConfigName: 'hello',
24
- });
25
-
26
- new integ.IntegTest(app, 'LambdaDeploymentConfigTest', {
15
+ new integ.IntegTest(app, 'EcsDeploymentConfigTest', {
27
16
  testCases: [stack],
28
17
  });
29
18
 
@@ -1,62 +1,240 @@
1
- import * as path from 'path';
2
1
  import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
3
- import * as lambda from 'aws-cdk-lib/aws-lambda';
2
+ import * as ec2 from 'aws-cdk-lib/aws-ec2';
3
+ import * as ecs from 'aws-cdk-lib/aws-ecs';
4
+ import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
4
5
  import * as cdk from 'aws-cdk-lib';
6
+ import * as integ from '@aws-cdk/integ-tests-alpha';
5
7
  import * as codedeploy from 'aws-cdk-lib/aws-codedeploy';
6
- import { STANDARD_NODEJS_RUNTIME } from '../../../config';
7
8
 
8
- const app = new cdk.App({
9
- postCliContext: {
10
- '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
9
+ /**
10
+ * Follow these instructions to manually test running a CodeDeploy deployment with the resources provisioned in this stack:
11
+ *
12
+ * 1. Deploy the stack:
13
+ ```
14
+ $ cdk deploy --app 'node integ.deployment-group.js' aws-cdk-codedeploy-ecs-dg
15
+ ```
16
+ *
17
+ * 2. Create a file called `appspec.json` with the following contents, replacing the placeholders with output values from the deployed stack:
18
+ ```
19
+ {
20
+ "version": 0.0,
21
+ "Resources": [
22
+ {
23
+ "TargetService": {
24
+ "Type": "AWS::ECS::Service",
25
+ "Properties": {
26
+ "TaskDefinition": "<PLACEHOLDER - NEW TASK DEFINITION>",
27
+ "LoadBalancerInfo": {
28
+ "ContainerName": "Container",
29
+ "ContainerPort": 80
30
+ },
31
+ "PlatformVersion": "LATEST",
32
+ "NetworkConfiguration": {
33
+ "awsvpcConfiguration": {
34
+ "subnets": [
35
+ "<PLACEHOLDER - SUBNET 1 ID>",
36
+ "<PLACEHOLDER - SUBNET 2 ID>",
37
+ ],
38
+ "securityGroups": [
39
+ "<PLACEHOLDER - SECURITY GROUP ID>"
40
+ ],
41
+ "assignPublicIp": "DISABLED"
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ]
48
+ }
49
+ ```
50
+ *
51
+ * 3. Start the deployment:
52
+ ```
53
+ $ appspec=$(jq -R -s '.' < appspec.json | sed 's/\\n//g')
54
+ $ aws deploy create-deployment \
55
+ --application-name <PLACEHOLDER - CODEDEPLOY APPLICATION NAME> \
56
+ --deployment-group-name <PLACEHOLDER - CODEDEPLOY DEPLOYMENT GROUP NAME> \
57
+ --description "AWS CDK integ test" \
58
+ --revision revisionType=AppSpecContent,appSpecContent={content="$appspec"}
59
+ ```
60
+ *
61
+ * 4. Wait for the deployment to complete successfully, providing the deployment ID from the previous step:
62
+ ```
63
+ $ aws deploy wait deployment-successful --deployment-id <PLACEHOLDER - DEPLOYMENT ID>
64
+ ```
65
+ *
66
+ * 5. Destroy the stack:
67
+ ```
68
+ $ cdk destroy --app 'node integ.deployment-group.js' aws-cdk-codedeploy-ecs-dg
69
+ ```
70
+ */
71
+
72
+ const app = new cdk.App();
73
+ const stack = new cdk.Stack(app, 'aws-cdk-codedeploy-ecs-dg');
74
+
75
+ // Network infrastructure
76
+ const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2, restrictDefaultSecurityGroup: false });
77
+
78
+ // ECS service
79
+ const cluster = new ecs.Cluster(stack, 'EcsCluster', {
80
+ vpc,
81
+ });
82
+ const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef');
83
+ taskDefinition.addContainer('Container', {
84
+ image: ecs.ContainerImage.fromRegistry('public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest'),
85
+ portMappings: [{ containerPort: 80 }],
86
+ });
87
+ const service = new ecs.FargateService(stack, 'FargateService', {
88
+ cluster,
89
+ taskDefinition,
90
+ deploymentController: {
91
+ type: ecs.DeploymentControllerType.CODE_DEPLOY,
11
92
  },
12
93
  });
13
- const stack = new cdk.Stack(app, 'aws-cdk-codedeploy-lambda');
14
94
 
15
- const handler = new lambda.Function(stack, 'Handler', {
16
- code: lambda.Code.fromAsset(path.join(__dirname, 'handler')),
17
- handler: 'index.handler',
18
- runtime: STANDARD_NODEJS_RUNTIME,
95
+ // A second task definition for testing a CodeDeploy deployment of the ECS service to a new task definition
96
+ const taskDefinition2 = new ecs.FargateTaskDefinition(stack, 'TaskDef2');
97
+ taskDefinition2.addContainer('Container', {
98
+ image: ecs.ContainerImage.fromRegistry('public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest'),
99
+ portMappings: [{ containerPort: 80 }],
19
100
  });
20
- const version = handler.currentVersion;
21
- const blueGreenAlias = new lambda.Alias(stack, 'Alias', {
22
- aliasName: 'alias',
23
- version,
101
+ service.node.addDependency(taskDefinition2);
102
+
103
+ // Load balancer
104
+ const loadBalancer = new elbv2.ApplicationLoadBalancer(stack, 'ServiceLB', {
105
+ vpc,
106
+ internetFacing: false,
24
107
  });
25
108
 
26
- const preHook = new lambda.Function(stack, 'PreHook', {
27
- code: lambda.Code.fromAsset(path.join(__dirname, 'preHook')),
28
- handler: 'index.handler',
29
- runtime: STANDARD_NODEJS_RUNTIME,
109
+ // Listeners
110
+ const prodListener = loadBalancer.addListener('ProdListener', {
111
+ port: 80, // port for production traffic
112
+ protocol: elbv2.ApplicationProtocol.HTTP,
30
113
  });
31
- const postHook = new lambda.Function(stack, 'PostHook', {
32
- code: lambda.Code.fromAsset(path.join(__dirname, 'postHook')),
33
- handler: 'index.handler',
34
- runtime: STANDARD_NODEJS_RUNTIME,
114
+ const testListener = loadBalancer.addListener('TestListener', {
115
+ port: 9002, // port for testing
116
+ protocol: elbv2.ApplicationProtocol.HTTP,
35
117
  });
36
118
 
37
- new codedeploy.LambdaDeploymentGroup(stack, 'BlueGreenDeployment', {
38
- alias: blueGreenAlias,
39
- deploymentConfig: codedeploy.LambdaDeploymentConfig.LINEAR_10PERCENT_EVERY_1MINUTE,
40
- alarms: [
41
- new cloudwatch.Alarm(stack, 'BlueGreenErrors', {
42
- comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
43
- threshold: 1,
44
- evaluationPeriods: 1,
45
- metric: blueGreenAlias.metricErrors(),
119
+ // Target groups
120
+ const blueTG = prodListener.addTargets('BlueTG', {
121
+ port: 80,
122
+ protocol: elbv2.ApplicationProtocol.HTTP,
123
+ targets: [
124
+ service.loadBalancerTarget({
125
+ containerName: 'Container',
126
+ containerPort: 80,
46
127
  }),
47
128
  ],
48
- preHook,
49
- postHook,
129
+ deregistrationDelay: cdk.Duration.seconds(30),
130
+ healthCheck: {
131
+ interval: cdk.Duration.seconds(5),
132
+ healthyHttpCodes: '200',
133
+ healthyThresholdCount: 2,
134
+ unhealthyThresholdCount: 3,
135
+ timeout: cdk.Duration.seconds(4),
136
+ },
50
137
  });
51
138
 
52
- const secondAlias = new lambda.Alias(stack, 'SecondAlias', {
53
- aliasName: 'secondAlias',
54
- version,
139
+ const greenTG = new elbv2.ApplicationTargetGroup(stack, 'GreenTG', {
140
+ vpc,
141
+ port: 80,
142
+ protocol: elbv2.ApplicationProtocol.HTTP,
143
+ targetType: elbv2.TargetType.IP,
144
+ deregistrationDelay: cdk.Duration.seconds(30),
145
+ healthCheck: {
146
+ interval: cdk.Duration.seconds(5),
147
+ healthyHttpCodes: '200',
148
+ healthyThresholdCount: 2,
149
+ unhealthyThresholdCount: 3,
150
+ timeout: cdk.Duration.seconds(4),
151
+ },
152
+ });
153
+
154
+ testListener.addTargetGroups('GreenTGTest', {
155
+ targetGroups: [greenTG],
55
156
  });
56
157
 
57
- new codedeploy.LambdaDeploymentGroup(stack, 'SecondDeployment', {
58
- alias: secondAlias,
59
- deploymentConfig: codedeploy.LambdaDeploymentConfig.CANARY_10PERCENT_5MINUTES,
158
+ prodListener.node.addDependency(greenTG);
159
+ testListener.node.addDependency(blueTG);
160
+ service.node.addDependency(testListener);
161
+ service.node.addDependency(greenTG);
162
+
163
+ // Alarms: monitor 500s and unhealthy hosts on target groups
164
+ const blueUnhealthyHosts = new cloudwatch.Alarm(stack, 'BlueUnhealthyHosts', {
165
+ alarmName: stack.stackName + '-Unhealthy-Hosts-Blue',
166
+ metric: blueTG.metricUnhealthyHostCount(),
167
+ threshold: 1,
168
+ evaluationPeriods: 2,
169
+ });
170
+
171
+ const blueApiFailure = new cloudwatch.Alarm(stack, 'Blue5xx', {
172
+ alarmName: stack.stackName + '-Http-500-Blue',
173
+ metric: blueTG.metricHttpCodeTarget(
174
+ elbv2.HttpCodeTarget.TARGET_5XX_COUNT,
175
+ { period: cdk.Duration.minutes(1) },
176
+ ),
177
+ threshold: 1,
178
+ evaluationPeriods: 1,
179
+ });
180
+
181
+ const greenUnhealthyHosts = new cloudwatch.Alarm(stack, 'GreenUnhealthyHosts', {
182
+ alarmName: stack.stackName + '-Unhealthy-Hosts-Green',
183
+ metric: greenTG.metricUnhealthyHostCount(),
184
+ threshold: 1,
185
+ evaluationPeriods: 2,
186
+ });
187
+
188
+ const greenApiFailure = new cloudwatch.Alarm(stack, 'Green5xx', {
189
+ alarmName: stack.stackName + '-Http-500-Green',
190
+ metric: greenTG.metricHttpCodeTarget(
191
+ elbv2.HttpCodeTarget.TARGET_5XX_COUNT,
192
+ { period: cdk.Duration.minutes(1) },
193
+ ),
194
+ threshold: 1,
195
+ evaluationPeriods: 1,
196
+ });
197
+
198
+ // Deployment group
199
+ const deploymentConfig = new codedeploy.EcsDeploymentConfig(stack, 'CanaryConfig', {
200
+ trafficRouting: codedeploy.TrafficRouting.timeBasedCanary({
201
+ interval: cdk.Duration.minutes(1),
202
+ percentage: 20,
203
+ }),
204
+ });
205
+
206
+ const dg = new codedeploy.EcsDeploymentGroup(stack, 'BlueGreenDG', {
207
+ alarms: [
208
+ blueUnhealthyHosts,
209
+ blueApiFailure,
210
+ greenUnhealthyHosts,
211
+ greenApiFailure,
212
+ ],
213
+ service,
214
+ blueGreenDeploymentConfig: {
215
+ blueTargetGroup: blueTG,
216
+ greenTargetGroup: greenTG,
217
+ listener: prodListener,
218
+ testListener,
219
+ terminationWaitTime: cdk.Duration.minutes(1),
220
+ },
221
+ deploymentConfig,
222
+ autoRollback: {
223
+ stoppedDeployment: true,
224
+ },
225
+ ignoreAlarmConfiguration: true,
226
+ });
227
+
228
+ // Outputs to use for manual testing
229
+ new cdk.CfnOutput(stack, 'NewTaskDefinition', { value: taskDefinition2.taskDefinitionArn });
230
+ new cdk.CfnOutput(stack, 'Subnet1Id', { value: vpc.privateSubnets[0].subnetId });
231
+ new cdk.CfnOutput(stack, 'Subnet2Id', { value: vpc.privateSubnets[1].subnetId });
232
+ new cdk.CfnOutput(stack, 'SecurityGroupId', { value: service.connections.securityGroups[0].securityGroupId });
233
+ new cdk.CfnOutput(stack, 'CodeDeployApplicationName', { value: dg.application.applicationName });
234
+ new cdk.CfnOutput(stack, 'CodeDeployDeploymentGroupName', { value: dg.deploymentGroupName });
235
+
236
+ new integ.IntegTest(app, 'EcsDeploymentGroupTest', {
237
+ testCases: [stack],
60
238
  });
61
239
 
62
240
  app.synth();
@@ -3,20 +3,30 @@ import * as cdk from 'aws-cdk-lib';
3
3
  import * as ecs from 'aws-cdk-lib/aws-ecs';
4
4
  import { IntegTest } from '@aws-cdk/integ-tests-alpha';
5
5
 
6
- const app = new cdk.App();
6
+ const app = new cdk.App({
7
+ postCliContext: {
8
+ '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
9
+ '@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy': false,
10
+ },
11
+ });
7
12
  const stack = new cdk.Stack(app, 'aws-ecs-integ-availability-zone-rebalancing');
8
13
 
9
14
  const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2, restrictDefaultSecurityGroup: false });
10
15
 
11
- const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });
16
+ const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc });
17
+
18
+ cluster.addCapacity('DefaultAutoScalingGroup', {
19
+ instanceType: new ec2.InstanceType('t2.micro'),
20
+ });
12
21
 
13
- const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef');
22
+ const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef');
14
23
 
15
24
  taskDefinition.addContainer('web', {
16
25
  image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
26
+ memoryLimitMiB: 256,
17
27
  });
18
28
 
19
- new ecs.FargateService(stack, 'FargateService', {
29
+ new ecs.Ec2Service(stack, 'FrontendService', {
20
30
  cluster,
21
31
  taskDefinition,
22
32
  availabilityZoneRebalancing: ecs.AvailabilityZoneRebalancing.ENABLED,
@@ -1,30 +1,53 @@
1
- import * as ec2 from 'aws-cdk-lib/aws-ec2';
2
- import * as kms from 'aws-cdk-lib/aws-kms';
1
+
2
+ import * as autoscaling from 'aws-cdk-lib/aws-autoscaling';
3
3
  import * as s3 from 'aws-cdk-lib/aws-s3';
4
+ import * as ec2 from 'aws-cdk-lib/aws-ec2';
4
5
  import * as cdk from 'aws-cdk-lib';
5
- import { Duration } from 'aws-cdk-lib';
6
6
  import * as integ from '@aws-cdk/integ-tests-alpha';
7
7
  import * as ecs from 'aws-cdk-lib/aws-ecs';
8
8
 
9
9
  const app = new cdk.App({
10
10
  postCliContext: {
11
+ '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
11
12
  '@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions': true,
13
+ '@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature': false,
14
+ '@aws-cdk/aws-ecs:disableEcsImdsBlocking': false,
15
+ '@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy': false,
12
16
  },
13
17
  });
14
18
  const stack = new cdk.Stack(app, 'aws-ecs-integ-enable-execute-command');
15
19
 
16
- const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2, restrictDefaultSecurityGroup: false });
20
+ const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 2 });
21
+
22
+ const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef');
23
+
24
+ taskDefinition.addContainer('web', {
25
+ image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
26
+ memoryReservationMiB: 256,
27
+ portMappings: [
28
+ {
29
+ containerPort: 80,
30
+ hostPort: 8080,
31
+ protocol: ecs.Protocol.TCP,
32
+ },
33
+ ],
34
+ });
17
35
 
18
- const kmsKey = new kms.Key(stack, 'KmsKey');
36
+ const execBucket = new s3.Bucket(stack, 'EcsExecBucket');
19
37
 
20
- const execBucket = new s3.Bucket(stack, 'EcsExecBucket', {
21
- encryptionKey: kmsKey,
38
+ const cp = new ecs.AsgCapacityProvider(stack, 'EC2CapacityProvider', {
39
+ autoScalingGroup: new autoscaling.AutoScalingGroup(stack, 'ASG', {
40
+ vpc,
41
+ instanceType: new ec2.InstanceType('t2.micro'),
42
+ machineImage: ecs.EcsOptimizedImage.amazonLinux2(),
43
+ }),
44
+ // This is to allow cdk destroy to work; otherwise deletion will hang bc ASG cannot be deleted
45
+ enableManagedTerminationProtection: false,
22
46
  });
23
47
 
24
- const cluster = new ecs.Cluster(stack, 'FargateCluster', {
48
+ const cluster = new ecs.Cluster(stack, 'EC2CPCluster', {
25
49
  vpc,
26
50
  executeCommandConfiguration: {
27
- kmsKey,
28
51
  logConfiguration: {
29
52
  s3Bucket: execBucket,
30
53
  s3EncryptionEnabled: true,
@@ -33,19 +56,9 @@ const cluster = new ecs.Cluster(stack, 'FargateCluster', {
33
56
  logging: ecs.ExecuteCommandLogging.OVERRIDE,
34
57
  },
35
58
  });
59
+ cluster.addAsgCapacityProvider(cp);
36
60
 
37
- const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef');
38
-
39
- taskDefinition.addContainer('web', {
40
- image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
41
- healthCheck: {
42
- command: ['CMD-SHELL', 'curl localhost:8000'],
43
- interval: Duration.seconds(60),
44
- timeout: Duration.seconds(40),
45
- },
46
- });
47
-
48
- new ecs.FargateService(stack, 'FargateService', {
61
+ new ecs.Ec2Service(stack, 'EC2Service', {
49
62
  cluster,
50
63
  taskDefinition,
51
64
  enableExecuteCommand: true,
@@ -53,12 +66,5 @@ new ecs.FargateService(stack, 'FargateService', {
53
66
 
54
67
  new integ.IntegTest(app, 'enable-execute-command-test', {
55
68
  testCases: [stack],
56
- diffAssets: true,
57
- cdkCommandOptions: {
58
- deploy: {
59
- args: {
60
- rollback: true,
61
- },
62
- },
63
- },
64
69
  });
70
+ app.synth();