From ed366ce812a94066de04e9862d6cbd1083bf5d9c Mon Sep 17 00:00:00 2001 From: Matsuda Date: Wed, 8 Jan 2025 05:46:37 +0900 Subject: [PATCH] feat(ecs): enable fault injection flag (#32598) ### Issue # (if applicable) N/A ### Reason for this change Add a missing property. ### Description of changes Add `enableFaultInjection` property. ### Describe any new or updated permissions being added No ### Description of how you validated changes Add unit test and integ test ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- ...efaultTestDeployAssert16EB808C.assets.json | 19 ++ ...aultTestDeployAssert16EB808C.template.json | 36 +++ ...inition-enable-fault-injection.assets.json | 19 ++ ...ition-enable-fault-injection.template.json | 124 ++++++++ .../cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 134 ++++++++ .../tree.json | 291 ++++++++++++++++++ ....task-definition-enable-fault-injection.ts | 27 ++ packages/aws-cdk-lib/aws-ecs/README.md | 22 +- .../aws-ecs/lib/base/task-definition.ts | 27 +- .../aws-ecs/test/task-definition.test.ts | 33 ++ 12 files changed, 736 insertions(+), 9 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/aws-ecs-task-definition-enable-fault-injection.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/aws-ecs-task-definition-enable-fault-injection.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.assets.json new file mode 100644 index 0000000000000..a55289a57059d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/aws-ecs-task-definition-enable-fault-injection.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/aws-ecs-task-definition-enable-fault-injection.assets.json new file mode 100644 index 0000000000000..9599cb8f22cdf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/aws-ecs-task-definition-enable-fault-injection.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "1f3359944a7dd8e04b4348673a74c55d7a4cf0f9645dcc981b79e1b9bb77dbd9": { + "source": { + "path": "aws-ecs-task-definition-enable-fault-injection.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "1f3359944a7dd8e04b4348673a74c55d7a4cf0f9645dcc981b79e1b9bb77dbd9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/aws-ecs-task-definition-enable-fault-injection.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/aws-ecs-task-definition-enable-fault-injection.template.json new file mode 100644 index 0000000000000..6074f7be58a3d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/aws-ecs-task-definition-enable-fault-injection.template.json @@ -0,0 +1,124 @@ +{ + "Resources": { + "Ec2TaskDefinitionTaskRole0B78BC85": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Ec2TaskDefinitionB25030BE": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest", + "Memory": 512, + "Name": "Ec2Container" + } + ], + "EnableFaultInjection": true, + "Family": "awsecstaskdefinitionenablefaultinjectionEc2TaskDefinition28DF45DB", + "NetworkMode": "host", + "RequiresCompatibilities": [ + "EC2" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "Ec2TaskDefinitionTaskRole0B78BC85", + "Arn" + ] + } + } + }, + "FargateTaskDefinitionTaskRoleE3C2BCAA": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "FargateTaskDefinition8E3B365E": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest", + "Memory": 512, + "Name": "FargateContainer" + } + ], + "Cpu": "256", + "EnableFaultInjection": true, + "Family": "awsecstaskdefinitionenablefaultinjectionFargateTaskDefinition203B68EF", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "FargateTaskDefinitionTaskRoleE3C2BCAA", + "Arn" + ] + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/cdk.out new file mode 100644 index 0000000000000..c6e612584e352 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"38.0.1"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/integ.json new file mode 100644 index 0000000000000..1779997e6b8dc --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "38.0.1", + "testCases": { + "TaskDefinitionEnableFaultInjection/DefaultTest": { + "stacks": [ + "aws-ecs-task-definition-enable-fault-injection" + ], + "assertionStack": "TaskDefinitionEnableFaultInjection/DefaultTest/DeployAssert", + "assertionStackName": "TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/manifest.json new file mode 100644 index 0000000000000..ffc554651abf2 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/manifest.json @@ -0,0 +1,134 @@ +{ + "version": "38.0.1", + "artifacts": { + "aws-ecs-task-definition-enable-fault-injection.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-ecs-task-definition-enable-fault-injection.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-ecs-task-definition-enable-fault-injection": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-ecs-task-definition-enable-fault-injection.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/1f3359944a7dd8e04b4348673a74c55d7a4cf0f9645dcc981b79e1b9bb77dbd9.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-ecs-task-definition-enable-fault-injection.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-ecs-task-definition-enable-fault-injection.assets" + ], + "metadata": { + "/aws-ecs-task-definition-enable-fault-injection/Ec2TaskDefinition/TaskRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Ec2TaskDefinitionTaskRole0B78BC85" + } + ], + "/aws-ecs-task-definition-enable-fault-injection/Ec2TaskDefinition/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Ec2TaskDefinitionB25030BE", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" + ] + } + ], + "/aws-ecs-task-definition-enable-fault-injection/FargateTaskDefinition/TaskRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FargateTaskDefinitionTaskRoleE3C2BCAA" + } + ], + "/aws-ecs-task-definition-enable-fault-injection/FargateTaskDefinition/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FargateTaskDefinition8E3B365E" + } + ], + "/aws-ecs-task-definition-enable-fault-injection/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-ecs-task-definition-enable-fault-injection/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-ecs-task-definition-enable-fault-injection" + }, + "TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "TaskDefinitionEnableFaultInjectionDefaultTestDeployAssert16EB808C.assets" + ], + "metadata": { + "/TaskDefinitionEnableFaultInjection/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/TaskDefinitionEnableFaultInjection/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "TaskDefinitionEnableFaultInjection/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/tree.json new file mode 100644 index 0000000000000..4c4bc5c338169 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.js.snapshot/tree.json @@ -0,0 +1,291 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-ecs-task-definition-enable-fault-injection": { + "id": "aws-ecs-task-definition-enable-fault-injection", + "path": "aws-ecs-task-definition-enable-fault-injection", + "children": { + "Ec2TaskDefinition": { + "id": "Ec2TaskDefinition", + "path": "aws-ecs-task-definition-enable-fault-injection/Ec2TaskDefinition", + "children": { + "TaskRole": { + "id": "TaskRole", + "path": "aws-ecs-task-definition-enable-fault-injection/Ec2TaskDefinition/TaskRole", + "children": { + "ImportTaskRole": { + "id": "ImportTaskRole", + "path": "aws-ecs-task-definition-enable-fault-injection/Ec2TaskDefinition/TaskRole/ImportTaskRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-task-definition-enable-fault-injection/Ec2TaskDefinition/TaskRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-task-definition-enable-fault-injection/Ec2TaskDefinition/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ECS::TaskDefinition", + "aws:cdk:cloudformation:props": { + "containerDefinitions": [ + { + "essential": true, + "image": "public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest", + "memory": 512, + "name": "Ec2Container" + } + ], + "enableFaultInjection": true, + "family": "awsecstaskdefinitionenablefaultinjectionEc2TaskDefinition28DF45DB", + "networkMode": "host", + "requiresCompatibilities": [ + "EC2" + ], + "taskRoleArn": { + "Fn::GetAtt": [ + "Ec2TaskDefinitionTaskRole0B78BC85", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ecs.CfnTaskDefinition", + "version": "0.0.0" + } + }, + "Ec2Container": { + "id": "Ec2Container", + "path": "aws-ecs-task-definition-enable-fault-injection/Ec2TaskDefinition/Ec2Container", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ecs.ContainerDefinition", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ecs.Ec2TaskDefinition", + "version": "0.0.0" + } + }, + "FargateTaskDefinition": { + "id": "FargateTaskDefinition", + "path": "aws-ecs-task-definition-enable-fault-injection/FargateTaskDefinition", + "children": { + "TaskRole": { + "id": "TaskRole", + "path": "aws-ecs-task-definition-enable-fault-injection/FargateTaskDefinition/TaskRole", + "children": { + "ImportTaskRole": { + "id": "ImportTaskRole", + "path": "aws-ecs-task-definition-enable-fault-injection/FargateTaskDefinition/TaskRole/ImportTaskRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-task-definition-enable-fault-injection/FargateTaskDefinition/TaskRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-ecs-task-definition-enable-fault-injection/FargateTaskDefinition/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ECS::TaskDefinition", + "aws:cdk:cloudformation:props": { + "containerDefinitions": [ + { + "essential": true, + "image": "public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest", + "memory": 512, + "name": "FargateContainer" + } + ], + "cpu": "256", + "enableFaultInjection": true, + "family": "awsecstaskdefinitionenablefaultinjectionFargateTaskDefinition203B68EF", + "memory": "512", + "networkMode": "awsvpc", + "requiresCompatibilities": [ + "FARGATE" + ], + "taskRoleArn": { + "Fn::GetAtt": [ + "FargateTaskDefinitionTaskRoleE3C2BCAA", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ecs.CfnTaskDefinition", + "version": "0.0.0" + } + }, + "FargateContainer": { + "id": "FargateContainer", + "path": "aws-ecs-task-definition-enable-fault-injection/FargateTaskDefinition/FargateContainer", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ecs.ContainerDefinition", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ecs.FargateTaskDefinition", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-ecs-task-definition-enable-fault-injection/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-ecs-task-definition-enable-fault-injection/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "TaskDefinitionEnableFaultInjection": { + "id": "TaskDefinitionEnableFaultInjection", + "path": "TaskDefinitionEnableFaultInjection", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "TaskDefinitionEnableFaultInjection/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "TaskDefinitionEnableFaultInjection/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "TaskDefinitionEnableFaultInjection/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TaskDefinitionEnableFaultInjection/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TaskDefinitionEnableFaultInjection/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.ts new file mode 100644 index 0000000000000..2eb3338db7262 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.task-definition-enable-fault-injection.ts @@ -0,0 +1,27 @@ +import * as cdk from 'aws-cdk-lib'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-task-definition-enable-fault-injection'); + +const ec2TaskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDefinition', { + enableFaultInjection: true, + networkMode: ecs.NetworkMode.HOST, +}); +ec2TaskDefinition.addContainer('Ec2Container', { + image: ecs.ContainerImage.fromRegistry('public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest'), + memoryLimitMiB: 512, +}); + +const fargateTaskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDefinition', { + enableFaultInjection: true, +}); +fargateTaskDefinition.addContainer('FargateContainer', { + image: ecs.ContainerImage.fromRegistry('public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest'), + memoryLimitMiB: 512, +}); + +new IntegTest(app, 'TaskDefinitionEnableFaultInjection', { + testCases: [stack], +}); diff --git a/packages/aws-cdk-lib/aws-ecs/README.md b/packages/aws-cdk-lib/aws-ecs/README.md index 76a0e49414600..9e765b3cb4b34 100644 --- a/packages/aws-cdk-lib/aws-ecs/README.md +++ b/packages/aws-cdk-lib/aws-ecs/README.md @@ -86,12 +86,12 @@ const cluster = new ecs.Cluster(this, 'Cluster', { }); ``` -To encrypt the fargate ephemeral storage configure a KMS key. +To encrypt the fargate ephemeral storage configure a KMS key. ```ts declare const key: kms.Key; -const cluster = new ecs.Cluster(this, 'Cluster', { - managedStorageConfiguration: { +const cluster = new ecs.Cluster(this, 'Cluster', { + managedStorageConfiguration: { fargateEphemeralStorageKmsKey: key, }, }); @@ -647,6 +647,22 @@ taskDefinition.addContainer('container', { }); ``` +### Enable Fault Injection +You can utilize fault injection with Amazon ECS on both Amazon EC2 and Fargate to test how their application responds to certain impairment scenarios. These tests provide information you can use to optimize your application's performance and resiliency. + +When fault injection is enabled, the Amazon ECS container agent allows tasks access to new fault injection endpoints. +Fault injection only works with tasks using the `AWS_VPC` or `HOST` network modes. + +For more infomation, see [Use fault injection with your Amazon ECS and Fargate workloads](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/fault-injection.html). + +To enable Fault Injection for the task definiton, set `enableFaultInjection` to true. + +```ts +new ecs.Ec2TaskDefinition(this, 'Ec2TaskDefinition', { + enableFaultInjection: true, +}); +``` + ## Docker labels You can add labels to the container with the `dockerLabels` property or with the `addDockerLabel` method: diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts index 7ab075ae777ce..c15e9ebdce9d5 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts @@ -99,6 +99,15 @@ export interface CommonTaskDefinitionProps { * @default - No volumes are passed to the Docker daemon on a container instance. */ readonly volumes?: Volume[]; + + /** + * Enables fault injection and allows for fault injection requests to be accepted from the task's containers. + * + * Fault injection only works with tasks using the {@link NetworkMode.AWS_VPC} or {@link NetworkMode.HOST} network modes. + * + * @default undefined - ECS default setting is false + */ + readonly enableFaultInjection?: boolean; } /** @@ -458,6 +467,11 @@ export class TaskDefinition extends TaskDefinitionBase { throw new Error('Cannot specify runtimePlatform in non-Fargate compatible tasks'); } + // https://docs.aws.amazon.com/AmazonECS/latest/developerguide/fault-injection.html + if (props.enableFaultInjection && ![NetworkMode.AWS_VPC, NetworkMode.HOST].includes(this.networkMode)) { + throw new Error(`Only AWS_VPC and HOST Network Modes are supported for enabling Fault Injection, got ${this.networkMode} mode.`); + } + this._executionRole = props.executionRole; this.taskRole = props.taskRole || new iam.Role(this, 'TaskRole', { @@ -514,6 +528,7 @@ export class TaskDefinition extends TaskDefinitionBase { cpuArchitecture: this.runtimePlatform?.cpuArchitecture?._cpuArchitecture, operatingSystemFamily: this.runtimePlatform?.operatingSystemFamily?._operatingSystemFamily, } : undefined, + enableFaultInjection: props.enableFaultInjection, }); if (props.placementConstraints) { @@ -565,7 +580,7 @@ export class TaskDefinition extends TaskDefinitionBase { private renderInferenceAccelerators(): CfnTaskDefinition.InferenceAcceleratorProperty[] { return this._inferenceAccelerators.map(renderInferenceAccelerator); - function renderInferenceAccelerator(inferenceAccelerator: InferenceAccelerator) : CfnTaskDefinition.InferenceAcceleratorProperty { + function renderInferenceAccelerator(inferenceAccelerator: InferenceAccelerator): CfnTaskDefinition.InferenceAcceleratorProperty { return { deviceName: inferenceAccelerator.deviceName, deviceType: inferenceAccelerator.deviceType, @@ -675,7 +690,7 @@ export class TaskDefinition extends TaskDefinitionBase { this.volumes.push(volume); } - private validateVolume(volume: Volume):void { + private validateVolume(volume: Volume): void { if (volume.configuredAtLaunch !== true) { return; } @@ -884,7 +899,7 @@ export class TaskDefinition extends TaskDefinitionBase { private checkFargateWindowsBasedTasksSize(cpu: string, memory: string, runtimePlatform: RuntimePlatform) { if (Number(cpu) === 1024) { - if (Number(memory) < 1024 || Number(memory) > 8192 || (Number(memory)% 1024 !== 0)) { + if (Number(memory) < 1024 || Number(memory) > 8192 || (Number(memory) % 1024 !== 0)) { throw new Error(`If provided cpu is ${cpu}, then memoryMiB must have a min of 1024 and a max of 8192, in 1024 increments. Provided memoryMiB was ${Number(memory)}.`); } } else if (Number(cpu) === 2048) { @@ -893,7 +908,7 @@ export class TaskDefinition extends TaskDefinitionBase { } } else if (Number(cpu) === 4096) { if (Number(memory) < 8192 || Number(memory) > 30720 || (Number(memory) % 1024 !== 0)) { - throw new Error(`If provided cpu is ${ cpu }, then memoryMiB must have a min of 8192 and a max of 30720, in 1024 increments.Provided memoryMiB was ${ Number(memory) }.`); + throw new Error(`If provided cpu is ${cpu}, then memoryMiB must have a min of 8192 and a max of 30720, in 1024 increments.Provided memoryMiB was ${Number(memory)}.`); } } else { throw new Error(`If operatingSystemFamily is ${runtimePlatform.operatingSystemFamily!._operatingSystemFamily}, then cpu must be in 1024 (1 vCPU), 2048 (2 vCPU), or 4096 (4 vCPU). Provided value was: ${cpu}`); @@ -1031,7 +1046,7 @@ export interface Volume { * * @default false */ - readonly configuredAtLaunch ?: boolean; + readonly configuredAtLaunch?: boolean; /** * This property is specified when you are using Docker volumes. @@ -1131,7 +1146,7 @@ export interface DockerVolumeConfiguration { * * @default No options */ - readonly driverOpts?: {[key: string]: string}; + readonly driverOpts?: { [key: string]: string }; /** * Custom metadata to add to your Docker volume. * diff --git a/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts b/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts index f098b3e89afcb..72af3300eb88d 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts @@ -457,6 +457,39 @@ describe('task definition', () => { Template.fromStack(stack); }).toThrow("ECS Container Container must have at least one of 'memoryLimitMiB' or 'memoryReservationMiB' specified"); }); + + test.each([true, false])('set enableFaultInjection to %s.', (enableFaultInjection) => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecs.TaskDefinition(stack, 'TD', { + cpu: '512', + compatibility: ecs.Compatibility.EC2, + enableFaultInjection, + networkMode: ecs.NetworkMode.HOST, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', { + EnableFaultInjection: enableFaultInjection, + }); + }); + + test('throws when enableFaultInjection is true with non AWSVPC or HOST Network Mode', () => { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + expect(() => { + new ecs.TaskDefinition(stack, 'TD', { + cpu: '512', + compatibility: ecs.Compatibility.EC2, + enableFaultInjection: true, + networkMode: ecs.NetworkMode.BRIDGE, + }); + }).toThrow('Only AWS_VPC and HOST Network Modes are supported for enabling Fault Injection, got bridge mode.'); + }); }); describe('When importing from an existing Task definition', () => {