konokenj.cdk-api-mcp-server 0.41.0__py3-none-any.whl → 0.43.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 (46) hide show
  1. cdk_api_mcp_server/__about__.py +1 -1
  2. cdk_api_mcp_server/resources/aws-cdk/constructs/@aws-cdk/aws-bedrock-alpha/README.md +540 -0
  3. cdk_api_mcp_server/resources/aws-cdk/constructs/@aws-cdk/aws-eks-v2-alpha/README.md +44 -46
  4. cdk_api_mcp_server/resources/aws-cdk/constructs/@aws-cdk/aws-glue-alpha/README.md +9 -9
  5. cdk_api_mcp_server/resources/aws-cdk/constructs/@aws-cdk/aws-lambda-python-alpha/README.md +6 -6
  6. cdk_api_mcp_server/resources/aws-cdk/constructs/@aws-cdk/aws-s3tables-alpha/README.md +28 -1
  7. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigatewayv2/integ.api-dualstack.ts +3 -4
  8. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigatewayv2/integ.api.ts +2 -4
  9. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigatewayv2/integ.stage.ts +7 -20
  10. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigatewayv2-authorizers/integ.iam.ts +34 -38
  11. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigatewayv2-integrations/integ.sqs.ts +58 -71
  12. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-certificatemanager/README.md +11 -0
  13. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-cloudwatch/README.md +13 -0
  14. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-cloudwatch/integ.dashboard-with-graphwidget-with-labels-visible.ts +92 -0
  15. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-codepipeline-actions/integ.pipeline-elastic-beanstalk-deploy.ts +1 -1
  16. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-cognito/README.md +11 -0
  17. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-cognito/integ.user-pool-client-explicit-props.ts +1 -0
  18. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/README.md +38 -13
  19. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/integ.dynamodb-v2.cci.ts +49 -0
  20. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/integ.dynamodb.cci.ts +27 -0
  21. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/integ.dynamodb.contirubtor-insights-for-gsi.ts +6 -2
  22. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/integ.table-v2-global.ts +9 -3
  23. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs/README.md +3 -0
  24. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs/integ.ebs-volume-initialization-rate.ts +80 -0
  25. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs-patterns/README.md +2 -0
  26. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ecs-patterns/integ.alb-fargate-service-smart-defaults.ts +143 -0
  27. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-events/README.md +25 -3
  28. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-events/integ.archive-customer-managed-key.ts +23 -0
  29. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-events-targets/README.md +64 -2
  30. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-rds/README.md +18 -0
  31. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-rds/integ.cluster.ts +1 -1
  32. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-s3-assets/integ.assets.bundling.docker-opts.ts +4 -1
  33. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-s3-deployment/README.md +18 -0
  34. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-sns/README.md +2 -0
  35. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-sns-subscriptions/integ.sns-sqs-subscription-filter.ts +75 -0
  36. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-sns-subscriptions/integ.sns-sqs.ts +21 -40
  37. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/integ.evaluate-expression-nodejs22.ts +27 -0
  38. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/integ.invoke-jsonata.ts +87 -80
  39. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/integ.invoke.ts +87 -69
  40. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-stepfunctions-tasks/integ.start-job-run.ts +102 -104
  41. cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/cx-api/FEATURE_FLAGS.md +28 -1
  42. {konokenj_cdk_api_mcp_server-0.41.0.dist-info → konokenj_cdk_api_mcp_server-0.43.0.dist-info}/METADATA +2 -2
  43. {konokenj_cdk_api_mcp_server-0.41.0.dist-info → konokenj_cdk_api_mcp_server-0.43.0.dist-info}/RECORD +46 -38
  44. {konokenj_cdk_api_mcp_server-0.41.0.dist-info → konokenj_cdk_api_mcp_server-0.43.0.dist-info}/WHEEL +0 -0
  45. {konokenj_cdk_api_mcp_server-0.41.0.dist-info → konokenj_cdk_api_mcp_server-0.43.0.dist-info}/entry_points.txt +0 -0
  46. {konokenj_cdk_api_mcp_server-0.41.0.dist-info → konokenj_cdk_api_mcp_server-0.43.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,112 +1,119 @@
1
- import * as path from 'path';
2
- import { IntegTest, ExpectedResult } from '@aws-cdk/integ-tests-alpha';
3
- import * as cdk from 'aws-cdk-lib';
4
- import * as apigateway from 'aws-cdk-lib/aws-apigateway';
5
- import * as events from 'aws-cdk-lib/aws-events';
1
+ import { Code, Function } from 'aws-cdk-lib/aws-lambda';
6
2
  import * as sfn from 'aws-cdk-lib/aws-stepfunctions';
7
- import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
8
- import * as tasks from 'aws-cdk-lib/aws-stepfunctions-tasks';
9
- import { password, username } from './my-lambda-handler';
3
+ import * as cdk from 'aws-cdk-lib';
4
+ import { LambdaInvoke } from 'aws-cdk-lib/aws-stepfunctions-tasks';
5
+ import { IntegTest, ExpectedResult } from '@aws-cdk/integ-tests-alpha';
6
+ import { STANDARD_NODEJS_RUNTIME } from '../../../config';
10
7
 
11
8
  /*
12
- * Creates an API Gateway instance with a GET method and mock integration,
13
- * secured with basic auth. It then creates a matching Connection and uses it
14
- * in a state machine with a task state to invoke the endpoint.
9
+ * Creates a state machine with a task state to invoke a Lambda function
10
+ * The state machine creates a couple of Lambdas that pass results forward
11
+ * and into a Choice state that validates the output.
12
+ *
13
+ * Stack verification steps:
14
+ * The generated State Machine can be executed from the CLI (or Step Functions console)
15
+ * and runs with an execution status of `Succeeded`.
15
16
  *
16
- * Stack verification steps :
17
- * * aws stepfunctions start-execution --state-machine-arn <deployed state machine arn> : should return execution arn
18
- * * aws stepfunctions describe-execution --execution-arn <execution-arn generated before> : should return status as SUCCEEDED
17
+ * -- aws stepfunctions start-execution --state-machine-arn <state-machine-arn-from-output> provides execution arn
18
+ * -- aws stepfunctions describe-execution --execution-arn <state-machine-arn-from-output> returns a status of `Succeeded`
19
19
  */
20
20
  const app = new cdk.App({
21
21
  postCliContext: {
22
22
  '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
23
23
  },
24
24
  });
25
- const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-http-invoke-integ');
25
+ const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-lambda-invoke-jsonata-integ');
26
26
 
27
- const authorizerHandler = new lambda.NodejsFunction(stack, 'AuthorizerHandler', {
28
- entry: path.resolve(__dirname, 'my-lambda-handler', 'index.ts'),
29
- handler: 'handler',
27
+ const submitJobLambda = new Function(stack, 'submitJobLambda', {
28
+ code: Code.fromInline(`exports.handler = async (event, context) => {
29
+ return {
30
+ statusCode: '200',
31
+ body: 'hello, world!',
32
+ ...event,
33
+ };
34
+ };`),
35
+ runtime: STANDARD_NODEJS_RUNTIME,
36
+ handler: 'index.handler',
30
37
  });
31
38
 
32
- const authorizer = new apigateway.TokenAuthorizer(stack, 'Authorizer', {
33
- handler: authorizerHandler,
34
- identitySource: 'method.request.header.Authorization',
35
- resultsCacheTtl: cdk.Duration.seconds(0),
36
- });
37
-
38
- const api = new apigateway.RestApi(stack, 'IntegRestApi');
39
-
40
- api.root.addResource('test').addMethod(
41
- 'GET',
42
- new apigateway.MockIntegration({
43
- integrationResponses: [
44
- {
45
- statusCode: '200',
46
- responseTemplates: {
47
- 'application/json': JSON.stringify({ message: 'Hello, tester!' }),
48
- },
49
- },
50
- ],
51
- passthroughBehavior: apigateway.PassthroughBehavior.NEVER,
52
- requestTemplates: {
53
- 'application/json': '{ "statusCode": 200 }',
54
- },
39
+ const submitJob = LambdaInvoke.jsonata(stack, 'Invoke Handler', {
40
+ lambdaFunction: submitJobLambda,
41
+ payload: sfn.TaskInput.fromObject({
42
+ execId: '{% $states.context.Execution.Id %}',
43
+ execInput: '{% $states.context.Execution.Input %}',
44
+ execName: '{% $states.context.Execution.Name %}',
45
+ execRoleArn: '{% $states.context.Execution.RoleArn %}',
46
+ execStartTime: '{% $states.context.Execution.StartTime %}',
47
+ stateEnteredTime: '{% $states.context.State.EnteredTime %}',
48
+ stateName: '{% $states.context.State.Name %}',
49
+ stateRetryCount: '{% $states.context.State.RetryCount %}',
50
+ stateMachineId: '{% $states.context.StateMachine.Id %}',
51
+ stateMachineName: '{% $states.context.StateMachine.Name %}',
55
52
  }),
56
- {
57
- authorizer,
58
- methodResponses: [
59
- {
60
- statusCode: '200',
61
- },
62
- ],
63
- },
64
- );
53
+ outputs: '{% $states.result.Payload %}',
54
+ });
65
55
 
66
- const connection = new events.Connection(stack, 'Connection', {
67
- authorization: events.Authorization.basic(username, cdk.SecretValue.unsafePlainText(password)),
56
+ const checkJobStateLambda = new Function(stack, 'checkJobStateLambda', {
57
+ code: Code.fromInline(`exports.handler = async function(event, context) {
58
+ const expectedFields = [
59
+ 'execId', 'execInput', 'execName', 'execRoleArn',
60
+ 'execStartTime', 'stateEnteredTime', 'stateName',
61
+ 'stateRetryCount', 'stateMachineId', 'stateMachineName',
62
+ ];
63
+ const fieldsAreSet = expectedFields.every(field => event[field] !== undefined);
64
+ return {
65
+ status: event.statusCode === '200' && fieldsAreSet ? 'SUCCEEDED' : 'FAILED'
66
+ };
67
+ };`),
68
+ runtime: STANDARD_NODEJS_RUNTIME,
69
+ handler: 'index.handler',
68
70
  });
69
71
 
70
- const httpInvokeTask = tasks.HttpInvoke.jsonata(stack, 'Invoke HTTP Endpoint', {
71
- apiRoot: api.urlForPath('/'),
72
- apiEndpoint: sfn.TaskInput.fromText('{% $states.input.apiEndpoint %}'),
73
- connection,
74
- method: sfn.TaskInput.fromText('GET'),
72
+ const checkJobState = LambdaInvoke.jsonata(stack, 'Check the job state', {
73
+ lambdaFunction: checkJobStateLambda,
75
74
  outputs: {
76
- ResponseBody: '{% $states.result.ResponseBody %}',
75
+ status: '{% $states.result.Payload.status %}',
77
76
  },
78
77
  });
79
78
 
79
+ const isComplete = sfn.Choice.jsonata(stack, 'Job Complete?');
80
+ const jobFailed = sfn.Fail.jsonata(stack, 'Job Failed', {
81
+ cause: 'Job Failed',
82
+ error: 'Received a status that was not 200',
83
+ });
84
+ const finalStatus = sfn.Pass.jsonata(stack, 'Final step');
85
+
86
+ const chain = sfn.Chain.start(submitJob)
87
+ .next(checkJobState)
88
+ .next(
89
+ isComplete
90
+ .when(sfn.Condition.jsonata("{% $states.input.status = 'FAILED' %}"), jobFailed)
91
+ .when(sfn.Condition.jsonata("{% $states.input.status = 'SUCCEEDED' %}"), finalStatus),
92
+ );
93
+
80
94
  const sm = new sfn.StateMachine(stack, 'StateMachine', {
81
- definition: httpInvokeTask,
95
+ definition: chain,
82
96
  timeout: cdk.Duration.seconds(30),
83
97
  });
84
98
 
85
- const testCase = new IntegTest(app, 'HttpInvokeTest', {
86
- testCases: [stack],
99
+ new cdk.CfnOutput(stack, 'stateMachineArn', {
100
+ value: sm.stateMachineArn,
87
101
  });
88
102
 
89
- // Start an execution
90
- const start = testCase.assertions.awsApiCall('@aws-sdk/client-sfn', 'StartExecution', {
91
- stateMachineArn: sm.stateMachineArn,
92
- input: JSON.stringify({
93
- apiEndpoint: '/test',
94
- }),
103
+ const integ = new IntegTest(app, 'IntegTest', {
104
+ testCases: [stack],
95
105
  });
96
-
97
- // describe the results of the execution
98
- const describe = testCase.assertions.awsApiCall('@aws-sdk/client-sfn', 'DescribeExecution', {
99
- executionArn: start.getAttString('executionArn'),
106
+ const res = integ.assertions.awsApiCall('@aws-sdk/client-sfn', 'StartExecution', {
107
+ stateMachineArn: sm.stateMachineArn,
100
108
  });
101
-
102
- // assert the results
103
- describe.expect(ExpectedResult.objectLike({
109
+ const executionArn = res.getAttString('executionArn');
110
+ integ.assertions.awsApiCall('@aws-sdk/client-sfn', 'DescribeExecution', {
111
+ executionArn,
112
+ }).expect(ExpectedResult.objectLike({
104
113
  status: 'SUCCEEDED',
105
- output: JSON.stringify({
106
- ResponseBody: {
107
- message: 'Hello, tester!',
108
- },
109
- }),
110
- }));
114
+ })).waitForAssertions({
115
+ totalTimeout: cdk.Duration.seconds(10),
116
+ interval: cdk.Duration.seconds(3),
117
+ });
111
118
 
112
119
  app.synth();
@@ -1,101 +1,119 @@
1
- import * as path from 'path';
2
- import { IntegTest, ExpectedResult } from '@aws-cdk/integ-tests-alpha';
3
- import * as cdk from 'aws-cdk-lib';
4
- import * as apigateway from 'aws-cdk-lib/aws-apigateway';
5
- import * as events from 'aws-cdk-lib/aws-events';
1
+ import { Code, Function } from 'aws-cdk-lib/aws-lambda';
6
2
  import * as sfn from 'aws-cdk-lib/aws-stepfunctions';
7
- import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
8
- import * as tasks from 'aws-cdk-lib/aws-stepfunctions-tasks';
9
- import { password, username } from './my-lambda-handler';
3
+ import * as cdk from 'aws-cdk-lib';
4
+ import { LambdaInvoke } from 'aws-cdk-lib/aws-stepfunctions-tasks';
5
+ import { IntegTest, ExpectedResult } from '@aws-cdk/integ-tests-alpha';
6
+ import { STANDARD_NODEJS_RUNTIME } from '../../../config';
10
7
 
11
8
  /*
12
- * Creates an API Gateway instance with a GET method and mock integration,
13
- * secured with basic auth. It then creates a matching Connection and uses it
14
- * in a state machine with a task state to invoke the endpoint.
9
+ * Creates a state machine with a task state to invoke a Lambda function
10
+ * The state machine creates a couple of Lambdas that pass results forward
11
+ * and into a Choice state that validates the output.
12
+ *
13
+ * Stack verification steps:
14
+ * The generated State Machine can be executed from the CLI (or Step Functions console)
15
+ * and runs with an execution status of `Succeeded`.
15
16
  *
16
- * Stack verification steps :
17
- * * aws stepfunctions start-execution --state-machine-arn <deployed state machine arn> : should return execution arn
18
- * * aws stepfunctions describe-execution --execution-arn <execution-arn generated before> : should return status as SUCCEEDED
17
+ * -- aws stepfunctions start-execution --state-machine-arn <state-machine-arn-from-output> provides execution arn
18
+ * -- aws stepfunctions describe-execution --execution-arn <state-machine-arn-from-output> returns a status of `Succeeded`
19
19
  */
20
20
  const app = new cdk.App({
21
21
  postCliContext: {
22
22
  '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
23
23
  },
24
24
  });
25
- const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-http-invoke-integ');
25
+ const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-lambda-invoke-integ');
26
26
 
27
- const authorizerHandler = new lambda.NodejsFunction(stack, 'AuthorizerHandler', {
28
- entry: path.resolve(__dirname, 'my-lambda-handler', 'index.ts'),
29
- handler: 'handler',
27
+ const submitJobLambda = new Function(stack, 'submitJobLambda', {
28
+ code: Code.fromInline(`exports.handler = async (event, context) => {
29
+ return {
30
+ statusCode: '200',
31
+ body: 'hello, world!',
32
+ ...event,
33
+ };
34
+ };`),
35
+ runtime: STANDARD_NODEJS_RUNTIME,
36
+ handler: 'index.handler',
30
37
  });
31
38
 
32
- const authorizer = new apigateway.TokenAuthorizer(stack, 'Authorizer', {
33
- handler: authorizerHandler,
34
- identitySource: 'method.request.header.Authorization',
35
- resultsCacheTtl: cdk.Duration.seconds(0),
39
+ const submitJob = new LambdaInvoke(stack, 'Invoke Handler', {
40
+ lambdaFunction: submitJobLambda,
41
+ payload: sfn.TaskInput.fromObject({
42
+ execId: sfn.JsonPath.executionId,
43
+ execInput: sfn.JsonPath.executionInput,
44
+ execName: sfn.JsonPath.executionName,
45
+ execRoleArn: sfn.JsonPath.executionRoleArn,
46
+ execStartTime: sfn.JsonPath.executionStartTime,
47
+ stateEnteredTime: sfn.JsonPath.stateEnteredTime,
48
+ stateName: sfn.JsonPath.stateName,
49
+ stateRetryCount: sfn.JsonPath.stateRetryCount,
50
+ stateMachineId: sfn.JsonPath.stateMachineId,
51
+ stateMachineName: sfn.JsonPath.stateMachineName,
52
+ }),
53
+ outputPath: '$.Payload',
36
54
  });
37
55
 
38
- const api = new apigateway.RestApi(stack, 'IntegRestApi');
56
+ const checkJobStateLambda = new Function(stack, 'checkJobStateLambda', {
57
+ code: Code.fromInline(`exports.handler = async function(event, context) {
58
+ const expectedFields = [
59
+ 'execId', 'execInput', 'execName', 'execRoleArn',
60
+ 'execStartTime', 'stateEnteredTime', 'stateName',
61
+ 'stateRetryCount', 'stateMachineId', 'stateMachineName',
62
+ ];
63
+ const fieldsAreSet = expectedFields.every(field => event[field] !== undefined);
64
+ return {
65
+ status: event.statusCode === '200' && fieldsAreSet ? 'SUCCEEDED' : 'FAILED'
66
+ };
67
+ };`),
68
+ runtime: STANDARD_NODEJS_RUNTIME,
69
+ handler: 'index.handler',
70
+ });
39
71
 
40
- api.root.addResource('test').addMethod(
41
- 'GET',
42
- new apigateway.MockIntegration({
43
- integrationResponses: [
44
- {
45
- statusCode: '200',
46
- responseTemplates: {
47
- 'application/json': JSON.stringify({ message: 'Hello, tester!' }),
48
- },
49
- },
50
- ],
51
- passthroughBehavior: apigateway.PassthroughBehavior.NEVER,
52
- requestTemplates: {
53
- 'application/json': '{ "statusCode": 200 }',
54
- },
55
- }),
56
- {
57
- authorizer,
58
- methodResponses: [
59
- {
60
- statusCode: '200',
61
- },
62
- ],
72
+ const checkJobState = new LambdaInvoke(stack, 'Check the job state', {
73
+ lambdaFunction: checkJobStateLambda,
74
+ resultSelector: {
75
+ status: sfn.JsonPath.stringAt('$.Payload.status'),
63
76
  },
64
- );
65
-
66
- const connection = new events.Connection(stack, 'Connection', {
67
- authorization: events.Authorization.basic(username, cdk.SecretValue.unsafePlainText(password)),
68
77
  });
69
78
 
70
- const httpInvokeTask = new tasks.HttpInvoke(stack, 'Invoke HTTP Endpoint', {
71
- apiRoot: api.urlForPath('/'),
72
- apiEndpoint: sfn.TaskInput.fromText('/test'),
73
- connection,
74
- method: sfn.TaskInput.fromText('GET'),
79
+ const isComplete = new sfn.Choice(stack, 'Job Complete?');
80
+ const jobFailed = new sfn.Fail(stack, 'Job Failed', {
81
+ cause: 'Job Failed',
82
+ error: 'Received a status that was not 200',
75
83
  });
84
+ const finalStatus = new sfn.Pass(stack, 'Final step');
85
+
86
+ const chain = sfn.Chain.start(submitJob)
87
+ .next(checkJobState)
88
+ .next(
89
+ isComplete
90
+ .when(sfn.Condition.stringEquals('$.status', 'FAILED'), jobFailed)
91
+ .when(sfn.Condition.stringEquals('$.status', 'SUCCEEDED'), finalStatus),
92
+ );
76
93
 
77
94
  const sm = new sfn.StateMachine(stack, 'StateMachine', {
78
- definition: httpInvokeTask,
95
+ definition: chain,
79
96
  timeout: cdk.Duration.seconds(30),
80
97
  });
81
98
 
82
- const testCase = new IntegTest(app, 'HttpInvokeTest', {
83
- testCases: [stack],
99
+ new cdk.CfnOutput(stack, 'stateMachineArn', {
100
+ value: sm.stateMachineArn,
84
101
  });
85
102
 
86
- // Start an execution
87
- const start = testCase.assertions.awsApiCall('StepFunctions', 'startExecution', {
88
- stateMachineArn: sm.stateMachineArn,
103
+ const integ = new IntegTest(app, 'IntegTest', {
104
+ testCases: [stack],
89
105
  });
90
-
91
- // describe the results of the execution
92
- const describe = testCase.assertions.awsApiCall('StepFunctions', 'describeExecution', {
93
- executionArn: start.getAttString('executionArn'),
106
+ const res = integ.assertions.awsApiCall('StepFunctions', 'startExecution', {
107
+ stateMachineArn: sm.stateMachineArn,
94
108
  });
95
-
96
- // assert the results
97
- describe.expect(ExpectedResult.objectLike({
109
+ const executionArn = res.getAttString('executionArn');
110
+ integ.assertions.awsApiCall('StepFunctions', 'describeExecution', {
111
+ executionArn,
112
+ }).expect(ExpectedResult.objectLike({
98
113
  status: 'SUCCEEDED',
99
- }));
114
+ })).waitForAssertions({
115
+ totalTimeout: cdk.Duration.seconds(10),
116
+ interval: cdk.Duration.seconds(3),
117
+ });
100
118
 
101
119
  app.synth();
@@ -1,124 +1,122 @@
1
- import * as databrew from 'aws-cdk-lib/aws-databrew';
1
+ import * as ec2 from 'aws-cdk-lib/aws-ec2';
2
+ import * as eks from 'aws-cdk-lib/aws-eks';
3
+ import { AwsAuthMapping } from 'aws-cdk-lib/aws-eks';
2
4
  import * as iam from 'aws-cdk-lib/aws-iam';
3
- import * as s3 from 'aws-cdk-lib/aws-s3';
4
5
  import * as sfn from 'aws-cdk-lib/aws-stepfunctions';
5
6
  import * as cdk from 'aws-cdk-lib';
6
- import { GlueDataBrewStartJobRun } from 'aws-cdk-lib/aws-stepfunctions-tasks';
7
+ import { Aws } from 'aws-cdk-lib';
8
+ import * as integ from '@aws-cdk/integ-tests-alpha';
9
+ import { KubectlV31Layer } from '@aws-cdk/lambda-layer-kubectl-v31';
10
+ import { EmrContainersStartJobRun, ReleaseLabel, VirtualClusterInput } from 'aws-cdk-lib/aws-stepfunctions-tasks';
11
+ import { EC2_RESTRICT_DEFAULT_SECURITY_GROUP } from 'aws-cdk-lib/cx-api';
7
12
 
8
- /*
13
+ /**
9
14
  * Stack verification steps:
10
- * * aws stepfunctions start-execution --state-machine-arn <deployed state machine arn> : should return execution arn
11
- * * aws stepfunctions describe-execution --execution-arn <exection-arn generated before> : should return status as SUCCEEDED
15
+ * Everything in the link below must be setup before running the state machine.
16
+ * @see https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-enable-IAM.html
17
+ * aws stepfunctions start-execution --state-machine-arn <deployed state machine arn> : should return execution arn
18
+ * aws stepfunctions describe-execution --execution-arn <exection-arn generated before> : should return status as SUCCEEDED
12
19
  */
13
20
 
14
- class GlueDataBrewJobStack extends cdk.Stack {
15
- constructor(scope: cdk.App, id: string, props: cdk.StackProps = {}) {
16
- super(scope, id, props);
21
+ const app = new cdk.App({
22
+ postCliContext: {
23
+ '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
24
+ '@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy': false,
25
+ },
26
+ });
27
+ const stack = new cdk.Stack(app, 'aws-stepfunctions-tasks-emr-containers-start-job-run');
28
+ stack.node.setContext(EC2_RESTRICT_DEFAULT_SECURITY_GROUP, false);
17
29
 
18
- const region = this.region;
30
+ const eksCluster = new eks.Cluster(stack, 'integration-test-eks-cluster', {
31
+ version: eks.KubernetesVersion.V1_30,
32
+ defaultCapacity: 3,
33
+ defaultCapacityInstance: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE),
34
+ kubectlLayer: new KubectlV31Layer(stack, 'KubectlLayer'),
35
+ });
19
36
 
20
- const outputBucket = new s3.Bucket(this, 'JobOutputBucket', {
21
- removalPolicy: cdk.RemovalPolicy.DESTROY,
22
- });
23
-
24
- const role = new iam.Role(this, 'DataBrew Role', {
25
- managedPolicies: [{
26
- managedPolicyArn: 'arn:aws:iam::aws:policy/service-role/AWSGlueDataBrewServiceRole',
27
- }],
28
- path: '/',
29
- assumedBy: new iam.ServicePrincipal('databrew.amazonaws.com'),
30
- inlinePolicies: {
31
- DataBrewPolicy: iam.PolicyDocument.fromJson({
32
- Statement: [{
33
- Effect: 'Allow',
34
- Action: [
35
- 's3:GetObject',
36
- 's3:PutObject',
37
- 's3:DeleteObject',
38
- 's3:ListBucket',
39
- ],
40
- Resource: [
41
- `arn:aws:s3:::databrew-public-datasets-${region}/*`,
42
- `arn:aws:s3:::databrew-public-datasets-${region}`,
43
- `${outputBucket.bucketArn}/*`,
44
- `${outputBucket.bucketArn}`,
45
- ],
46
- }],
47
- }),
37
+ const virtualCluster = new cdk.CfnResource(stack, 'Virtual Cluster', {
38
+ type: 'AWS::EMRContainers::VirtualCluster',
39
+ properties: {
40
+ ContainerProvider: {
41
+ Id: eksCluster.clusterName,
42
+ Info: {
43
+ EksInfo: {
44
+ Namespace: 'default',
45
+ },
48
46
  },
49
- });
47
+ Type: 'EKS',
48
+ },
49
+ Name: 'Virtual-Cluster-Name',
50
+ },
51
+ });
50
52
 
51
- const recipe = new databrew.CfnRecipe(this, 'DataBrew Recipe', {
52
- name: 'recipe-1',
53
- steps: [
54
- {
55
- action: {
56
- operation: 'UPPER_CASE',
57
- parameters: {
58
- sourceColumn: 'description',
59
- },
60
- },
61
- },
62
- {
63
- action: {
64
- operation: 'DELETE',
65
- parameters: {
66
- sourceColumn: 'doc_id',
67
- },
68
- },
69
- },
70
- ],
71
- });
53
+ const emrRole = eksCluster.addManifest('emrRole', {
54
+ apiVersion: 'rbac.authorization.k8s.io/v1',
55
+ kind: 'Role',
56
+ metadata: { name: 'emr-containers', namespace: 'default' },
57
+ rules: [
58
+ { apiGroups: [''], resources: ['namespaces'], verbs: ['get'] },
59
+ { apiGroups: [''], resources: ['serviceaccounts', 'services', 'configmaps', 'events', 'pods', 'pods/log'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'deletecollection', 'annotate', 'patch', 'label'] },
60
+ { apiGroups: [''], resources: ['secrets'], verbs: ['create', 'patch', 'delete', 'watch'] },
61
+ { apiGroups: ['apps'], resources: ['statefulsets', 'deployments'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'annotate', 'patch', 'label'] },
62
+ { apiGroups: ['batch'], resources: ['jobs'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'annotate', 'patch', 'label'] },
63
+ { apiGroups: ['extensions'], resources: ['ingresses'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'annotate', 'patch', 'label'] },
64
+ { apiGroups: ['rbac.authorization.k8s.io'], resources: ['roles', 'rolebindings'], verbs: ['get', 'list', 'watch', 'describe', 'create', 'edit', 'delete', 'deletecollection', 'annotate', 'patch', 'label'] },
65
+ ],
66
+ });
72
67
 
73
- const dataset = new databrew.CfnDataset(this, 'DataBrew Dataset', {
74
- input: {
75
- s3InputDefinition: {
76
- bucket: `databrew-public-datasets-${region}`,
77
- key: 'votes.csv',
78
- },
79
- },
80
- name: 'dataset-1',
81
- });
68
+ const emrRoleBind = eksCluster.addManifest('emrRoleBind', {
69
+ apiVersion: 'rbac.authorization.k8s.io/v1',
70
+ kind: 'RoleBinding',
71
+ metadata: { name: 'emr-containers', namespace: 'default' },
72
+ subjects: [{ kind: 'User', name: 'emr-containers', apiGroup: 'rbac.authorization.k8s.io' }],
73
+ roleRef: { kind: 'Role', name: 'emr-containers', apiGroup: 'rbac.authorization.k8s.io' },
74
+ });
82
75
 
83
- const project = new databrew.CfnProject(this, 'DataBrew Project', {
84
- name: 'project-1',
85
- roleArn: role.roleArn,
86
- datasetName: dataset.name,
87
- recipeName: recipe.name,
88
- });
89
- project.addDependency(dataset);
90
- project.addDependency(recipe);
76
+ emrRoleBind.node.addDependency(emrRole);
91
77
 
92
- const job = new databrew.CfnJob(this, 'DataBrew Job', {
93
- name: 'job-1',
94
- type: 'RECIPE',
95
- projectName: project.name,
96
- roleArn: role.roleArn,
97
- outputs: [{
98
- location: {
99
- bucket: outputBucket.bucketName,
100
- },
101
- }],
102
- });
103
- job.addDependency(project);
78
+ const emrServiceRole = iam.Role.fromRoleArn(stack, 'emrServiceRole', 'arn:aws:iam::'+Aws.ACCOUNT_ID+':role/AWSServiceRoleForAmazonEMRContainers');
79
+ const authMapping: AwsAuthMapping = { groups: [], username: 'emr-containers' };
80
+ eksCluster.awsAuth.addRoleMapping(emrServiceRole, authMapping);
81
+
82
+ virtualCluster.node.addDependency(emrRoleBind);
83
+ virtualCluster.node.addDependency(eksCluster.awsAuth);
104
84
 
105
- const startGlueDataBrewJob = new GlueDataBrewStartJobRun(this, 'Start DataBrew Job run', {
106
- name: job.name,
107
- });
85
+ const startJobRunJob = new EmrContainersStartJobRun(stack, 'Start a Job Run', {
86
+ virtualCluster: VirtualClusterInput.fromVirtualClusterId(virtualCluster.getAtt('Id').toString()),
87
+ releaseLabel: ReleaseLabel.EMR_6_2_0,
88
+ jobName: 'EMR-Containers-Job',
89
+ jobDriver: {
90
+ sparkSubmitJobDriver: {
91
+ entryPoint: sfn.TaskInput.fromText('local:///usr/lib/spark/examples/src/main/python/pi.py'),
92
+ entryPointArguments: sfn.TaskInput.fromObject(['2']),
93
+ sparkSubmitParameters: '--conf spark.driver.memory=512M --conf spark.kubernetes.driver.request.cores=0.2 --conf spark.kubernetes.executor.request.cores=0.2 --conf spark.sql.shuffle.partitions=60 --conf spark.dynamicAllocation.enabled=false',
94
+ },
95
+ },
96
+ });
108
97
 
109
- const chain = sfn.Chain.start(startGlueDataBrewJob);
98
+ const chain = sfn.Chain.start(startJobRunJob);
110
99
 
111
- const sm = new sfn.StateMachine(this, 'StateMachine', {
112
- definition: chain,
113
- timeout: cdk.Duration.seconds(30),
114
- });
100
+ const sm = new sfn.StateMachine(stack, 'StateMachine', {
101
+ definition: chain,
102
+ timeout: cdk.Duration.seconds(1000),
103
+ });
115
104
 
116
- new cdk.CfnOutput(this, 'stateMachineArn', {
117
- value: sm.stateMachineArn,
118
- });
119
- }
120
- }
105
+ new cdk.CfnOutput(stack, 'stateMachineArn', {
106
+ value: sm.stateMachineArn,
107
+ });
108
+
109
+ new integ.IntegTest(app, 'aws-stepfunctions-tasks-emr-containers-start-job-run-integ', {
110
+ testCases: [stack],
111
+ // Test includes assets that are updated weekly. If not disabled, the upgrade PR will fail.
112
+ diffAssets: false,
113
+ cdkCommandOptions: {
114
+ deploy: {
115
+ args: {
116
+ rollback: true,
117
+ },
118
+ },
119
+ },
120
+ });
121
121
 
122
- const app = new cdk.App();
123
- new GlueDataBrewJobStack(app, 'aws-stepfunctions-tasks-databrew-start-job-run-integ');
124
122
  app.synth();