From 5dcb7b933a663eb30c8454cc35158024e2827dbb Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Fri, 16 Feb 2024 19:55:07 -0800 Subject: [PATCH 1/6] fix(batch): Windows does not support readonlyRootFilesystem --- .../aws-batch/lib/ecs-container-definition.ts | 5 +++++ .../aws-batch/test/ecs-container-definition.test.ts | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts index 8d5369d7c88d9..52a24c5965962 100644 --- a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts +++ b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts @@ -1057,6 +1057,11 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im this.fargateCpuArchitecture = props.fargateCpuArchitecture; this.fargateOperatingSystemFamily = props.fargateOperatingSystemFamily; + if (this.fargateOperatingSystemFamily?._operatingSystemFamily.toLowerCase().includes('windows') && this.readonlyRootFilesystem) { + // see https://kubernetes.io/docs/concepts/windows/intro/ + throw new Error('Readonly root filesystem is not possible on Windows; write access is required for registry & system processes to run inside the container'); + } + // validates ephemeralStorageSize is within limits if (props.ephemeralStorageSize) { if (props.ephemeralStorageSize.toGibibytes() > 200) { diff --git a/packages/aws-cdk-lib/aws-batch/test/ecs-container-definition.test.ts b/packages/aws-cdk-lib/aws-batch/test/ecs-container-definition.test.ts index 038ba05965020..caae20862e9a6 100644 --- a/packages/aws-cdk-lib/aws-batch/test/ecs-container-definition.test.ts +++ b/packages/aws-cdk-lib/aws-batch/test/ecs-container-definition.test.ts @@ -1067,4 +1067,14 @@ describe('Fargate containers', () => { }), })).toThrow("ECS Fargate container 'EcsFargateContainer2' specifies 'ephemeralStorageSize' at 201 > 200 GB"); }); + + test('readonlyRootFilesystem can\'t be true with Windows family', () => { + expect(() => new EcsJobDefinition(stack, 'ECSJobDefn', { + container: new EcsFargateContainerDefinition(stack, 'EcsFargateContainer', { + ...defaultContainerProps, + readonlyRootFilesystem: true, + fargateOperatingSystemFamily: ecs.OperatingSystemFamily.WINDOWS_SERVER_2004_CORE, + }), + })).toThrow('Readonly root filesystem is not possible on Windows; write access is required for registry & system processes to run inside the container'); + }); }); From 854147d77492ec92beb151210addb82156daf973 Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Thu, 22 Feb 2024 11:52:20 -0500 Subject: [PATCH 2/6] remove readonly entirely --- .../manifest.json | 25 +- .../stack.assets.json | 4 +- .../stack.template.json | 100 ++++ .../tree.json | 504 ++++++++++++------ .../test/integ.ecs-job-definition.ts | 12 + .../aws-batch/lib/ecs-container-definition.ts | 22 +- .../test/ecs-container-definition.test.ts | 19 +- 7 files changed, 513 insertions(+), 173 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/manifest.json index d4e5db68eb0de..4b40b7a3b001e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/manifest.json @@ -18,7 +18,7 @@ "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}/80ca79d29007dc0a645c6568c47e0730a748e22b27eaba47a7336b97d459edcc.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/9b59badf02feb83b2f2747da9bbab479669d1efa47acadf76785d017660f7d03.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -247,10 +247,7 @@ "/stack/ECSFargateJobDefn/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ECSFargateJobDefn327BE725", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" - ] + "data": "ECSFargateJobDefn327BE725" } ], "/stack/EcsDockerContainer/ExecutionRole/Resource": [ @@ -271,6 +268,24 @@ "data": "ECSDockerJobDefnF388CFCF" } ], + "/stack/WindowsFargateContainer/ExecutionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "WindowsFargateContainerExecutionRoleAE15A6C1" + } + ], + "/stack/WindowsFargateContainer/ExecutionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "WindowsFargateContainerExecutionRoleDefaultPolicyA16F3283" + } + ], + "/stack/WindowsJobDefinitio/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "WindowsJobDefinitio0652E08A" + } + ], "/stack/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/stack.assets.json index be9330c4ed096..5af4252f1a2d2 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/stack.assets.json @@ -1,7 +1,7 @@ { "version": "36.0.0", "files": { - "80ca79d29007dc0a645c6568c47e0730a748e22b27eaba47a7336b97d459edcc": { + "9b59badf02feb83b2f2747da9bbab479669d1efa47acadf76785d017660f7d03": { "source": { "path": "stack.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "80ca79d29007dc0a645c6568c47e0730a748e22b27eaba47a7336b97d459edcc.json", + "objectKey": "9b59badf02feb83b2f2747da9bbab479669d1efa47acadf76785d017660f7d03.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/stack.template.json index 07857e0e45000..4f3da7e9b5dcc 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/stack.template.json @@ -997,6 +997,106 @@ "Timeout": {}, "Type": "container" } + }, + "WindowsFargateContainerExecutionRoleAE15A6C1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "WindowsFargateContainerExecutionRoleDefaultPolicyA16F3283": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/batch/job:*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "WindowsFargateContainerExecutionRoleDefaultPolicyA16F3283", + "Roles": [ + { + "Ref": "WindowsFargateContainerExecutionRoleAE15A6C1" + } + ] + } + }, + "WindowsJobDefinitio0652E08A": { + "Type": "AWS::Batch::JobDefinition", + "Properties": { + "ContainerProperties": { + "Environment": [], + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "WindowsFargateContainerExecutionRoleAE15A6C1", + "Arn" + ] + }, + "FargatePlatformConfiguration": {}, + "Image": "mcr.microsoft.com/dotnet/framework/runtime:4.7.2", + "NetworkConfiguration": { + "AssignPublicIp": "DISABLED" + }, + "ResourceRequirements": [ + { + "Type": "MEMORY", + "Value": "8192" + }, + { + "Type": "VCPU", + "Value": "2" + } + ], + "RuntimePlatform": { + "CpuArchitecture": "X86_64", + "OperatingSystemFamily": "WINDOWS_SERVER_2019_FULL" + } + }, + "JobDefinitionName": "windows-job-definition", + "PlatformCapabilities": [ + "FARGATE" + ], + "RetryStrategy": {}, + "Timeout": {}, + "Type": "container" + } } }, "Parameters": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/tree.json index a6452a3856934..6d0429bfdff10 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.js.snapshot/tree.json @@ -31,8 +31,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "PublicSubnet1": { @@ -75,16 +75,16 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "Acl": { "id": "Acl", "path": "stack/vpc/PublicSubnet1/Acl", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "RouteTable": { @@ -105,8 +105,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "RouteTableAssociation": { @@ -124,8 +124,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "DefaultRoute": { @@ -144,8 +144,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "EIP": { @@ -164,8 +164,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "NATGateway": { @@ -192,14 +192,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "PublicSubnet2": { @@ -242,16 +242,16 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "Acl": { "id": "Acl", "path": "stack/vpc/PublicSubnet2/Acl", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "RouteTable": { @@ -272,8 +272,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "RouteTableAssociation": { @@ -291,8 +291,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "DefaultRoute": { @@ -311,8 +311,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "EIP": { @@ -331,8 +331,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "NATGateway": { @@ -359,14 +359,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "PrivateSubnet1": { @@ -409,16 +409,16 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "Acl": { "id": "Acl", "path": "stack/vpc/PrivateSubnet1/Acl", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "RouteTable": { @@ -439,8 +439,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "RouteTableAssociation": { @@ -458,8 +458,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "DefaultRoute": { @@ -478,14 +478,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "PrivateSubnet2": { @@ -528,16 +528,16 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "Acl": { "id": "Acl", "path": "stack/vpc/PrivateSubnet2/Acl", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "RouteTable": { @@ -558,8 +558,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "RouteTableAssociation": { @@ -577,8 +577,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "DefaultRoute": { @@ -597,14 +597,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "IGW": { @@ -622,8 +622,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "VPCGW": { @@ -641,14 +641,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.Vpc", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "myFileSystem": { @@ -691,8 +691,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_efs.CfnFileSystem", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "EfsSecurityGroup": { @@ -725,14 +725,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "EfsMountTarget-PrivateSubnet1": { @@ -758,8 +758,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_efs.CfnMountTarget", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "EfsMountTarget-PrivateSubnet2": { @@ -785,14 +785,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_efs.CfnMountTarget", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_efs.FileSystem", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "mySecret": { @@ -809,14 +809,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.Secret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "anotherSecret": { @@ -833,14 +833,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.Secret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "ssm": { @@ -858,14 +858,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ssm.CfnParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ssm.StringParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "myContainer": { @@ -880,8 +880,8 @@ "id": "ImportExecutionRole", "path": "stack/myContainer/ExecutionRole/ImportExecutionRole", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "Resource": { @@ -905,8 +905,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnRole", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "DefaultPolicy": { @@ -1007,34 +1007,34 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Policy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Role", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "batchDefaultLogGroup": { "id": "batchDefaultLogGroup", "path": "stack/myContainer/batchDefaultLogGroup", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.EcsEc2ContainerDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "ECSJobDefn": { @@ -1167,14 +1167,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.CfnJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.EcsJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "myFargateContainer": { @@ -1189,8 +1189,8 @@ "id": "ImportExecutionRole", "path": "stack/myFargateContainer/ExecutionRole/ImportExecutionRole", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "Resource": { @@ -1214,8 +1214,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnRole", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "DefaultPolicy": { @@ -1269,34 +1269,34 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Policy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Role", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "batchDefaultLogGroup": { "id": "batchDefaultLogGroup", "path": "stack/myFargateContainer/batchDefaultLogGroup", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.EcsFargateContainerDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "ECSFargateJobDefn": { @@ -1378,14 +1378,14 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.CfnJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.EcsJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "dockerImageAsset": { @@ -1396,22 +1396,22 @@ "id": "Staging", "path": "stack/dockerImageAsset/Staging", "constructInfo": { - "fqn": "aws-cdk-lib.AssetStaging", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "Repository": { "id": "Repository", "path": "stack/dockerImageAsset/Repository", "constructInfo": { - "fqn": "aws-cdk-lib.aws_ecr.RepositoryBase", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ecr_assets.DockerImageAsset", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "EcsDockerContainer": { @@ -1426,8 +1426,8 @@ "id": "ImportExecutionRole", "path": "stack/EcsDockerContainer/ExecutionRole/ImportExecutionRole", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "Resource": { @@ -1451,8 +1451,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnRole", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "DefaultPolicy": { @@ -1542,34 +1542,34 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Policy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Role", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "batchDefaultLogGroup": { "id": "batchDefaultLogGroup", "path": "stack/EcsDockerContainer/batchDefaultLogGroup", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.EcsEc2ContainerDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "ECSDockerJobDefn": { @@ -1614,36 +1614,216 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.CfnJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_batch.EcsJobDefinition", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "WindowsFargateContainer": { + "id": "WindowsFargateContainer", + "path": "stack/WindowsFargateContainer", + "children": { + "ExecutionRole": { + "id": "ExecutionRole", + "path": "stack/WindowsFargateContainer/ExecutionRole", + "children": { + "ImportExecutionRole": { + "id": "ImportExecutionRole", + "path": "stack/WindowsFargateContainer/ExecutionRole/ImportExecutionRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Resource": { + "id": "Resource", + "path": "stack/WindowsFargateContainer/ExecutionRole/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": "constructs.Construct", + "version": "10.3.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "stack/WindowsFargateContainer/ExecutionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "stack/WindowsFargateContainer/ExecutionRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/batch/job:*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "WindowsFargateContainerExecutionRoleDefaultPolicyA16F3283", + "roles": [ + { + "Ref": "WindowsFargateContainerExecutionRoleAE15A6C1" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "batchDefaultLogGroup": { + "id": "batchDefaultLogGroup", + "path": "stack/WindowsFargateContainer/batchDefaultLogGroup", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "WindowsJobDefinitio": { + "id": "WindowsJobDefinitio", + "path": "stack/WindowsJobDefinitio", + "children": { + "Resource": { + "id": "Resource", + "path": "stack/WindowsJobDefinitio/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Batch::JobDefinition", + "aws:cdk:cloudformation:props": { + "containerProperties": { + "image": "mcr.microsoft.com/dotnet/framework/runtime:4.7.2", + "environment": [], + "executionRoleArn": { + "Fn::GetAtt": [ + "WindowsFargateContainerExecutionRoleAE15A6C1", + "Arn" + ] + }, + "resourceRequirements": [ + { + "type": "MEMORY", + "value": "8192" + }, + { + "type": "VCPU", + "value": "2" + } + ], + "fargatePlatformConfiguration": {}, + "networkConfiguration": { + "assignPublicIp": "DISABLED" + }, + "runtimePlatform": { + "cpuArchitecture": "X86_64", + "operatingSystemFamily": "WINDOWS_SERVER_2019_FULL" + } + }, + "jobDefinitionName": "windows-job-definition", + "platformCapabilities": [ + "FARGATE" + ], + "retryStrategy": {}, + "timeout": {}, + "type": "container" + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "stack/BootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "stack/CheckBootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnRule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.Stack", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "BatchEcsJobDefinitionTest": { @@ -1670,22 +1850,22 @@ "id": "BootstrapVersion", "path": "BatchEcsJobDefinitionTest/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "BatchEcsJobDefinitionTest/DefaultTest/DeployAssert/CheckBootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnRule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.Stack", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, @@ -1710,8 +1890,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.App", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.ts index ec2ac7fdeaec8..42bd10cb5ebfc 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-batch/test/integ.ecs-job-definition.ts @@ -92,6 +92,18 @@ new batch.EcsJobDefinition(stack, 'ECSDockerJobDefn', { }), }); +// can successfully launch a Windows container +new batch.EcsJobDefinition(stack, 'WindowsJobDefinitio', { + jobDefinitionName: 'windows-job-definition', + container: new batch.EcsFargateContainerDefinition(stack, 'WindowsFargateContainer', { + image: ecs.ContainerImage.fromRegistry('mcr.microsoft.com/dotnet/framework/runtime:4.7.2'), + memory: Size.gibibytes(8), + cpu: 2, + fargateCpuArchitecture: ecs.CpuArchitecture.X86_64, + fargateOperatingSystemFamily: ecs.OperatingSystemFamily.WINDOWS_SERVER_2019_FULL, + }), +}); + new integ.IntegTest(app, 'BatchEcsJobDefinitionTest', { testCases: [stack], }); diff --git a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts index 52a24c5965962..1d0365ec20b29 100644 --- a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts +++ b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts @@ -703,6 +703,13 @@ abstract class EcsContainerDefinitionBase extends Construct implements IEcsConta }; } + protected isWindows(operatingSystemFamily?: string): boolean { + if (operatingSystemFamily?.toLowerCase().includes('windows')) { + return true; + } + return false; + } + public addVolume(volume: EcsVolume): void { this.volumes.push(volume); } @@ -1057,7 +1064,7 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im this.fargateCpuArchitecture = props.fargateCpuArchitecture; this.fargateOperatingSystemFamily = props.fargateOperatingSystemFamily; - if (this.fargateOperatingSystemFamily?._operatingSystemFamily.toLowerCase().includes('windows') && this.readonlyRootFilesystem) { + if (this.isWindows(this.fargateOperatingSystemFamily?._operatingSystemFamily) && this.readonlyRootFilesystem) { // see https://kubernetes.io/docs/concepts/windows/intro/ throw new Error('Readonly root filesystem is not possible on Windows; write access is required for registry & system processes to run inside the container'); } @@ -1076,7 +1083,9 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im * @internal */ public _renderContainerDefinition(): CfnJobDefinition.ContainerPropertiesProperty { - return { + const operatingSystemFamily = this.fargateOperatingSystemFamily?._operatingSystemFamily; + + let containerDef = { ...super._renderContainerDefinition(), ephemeralStorage: this.ephemeralStorageSize? { sizeInGiB: this.ephemeralStorageSize?.toGibibytes(), @@ -1089,9 +1098,16 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im }, runtimePlatform: { cpuArchitecture: this.fargateCpuArchitecture?._cpuArchitecture, - operatingSystemFamily: this.fargateOperatingSystemFamily?._operatingSystemFamily, + operatingSystemFamily, }, }; + + // readonlyRootFilesystem isn't applicable to Windows, see https://kubernetes.io/docs/concepts/windows/intro/ + if (this.isWindows(operatingSystemFamily)) { + containerDef.readonlyRootFilesystem = undefined; + } + + return containerDef; }; } diff --git a/packages/aws-cdk-lib/aws-batch/test/ecs-container-definition.test.ts b/packages/aws-cdk-lib/aws-batch/test/ecs-container-definition.test.ts index caae20862e9a6..c771cd19a3d90 100644 --- a/packages/aws-cdk-lib/aws-batch/test/ecs-container-definition.test.ts +++ b/packages/aws-cdk-lib/aws-batch/test/ecs-container-definition.test.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import { capitalizePropertyNames } from './utils'; import { Size, Stack } from '../..'; import * as cdk from '../..'; -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import { Vpc } from '../../aws-ec2'; import * as ecr from '../../aws-ecr'; import { DockerImageAsset } from '../../aws-ecr-assets'; @@ -1077,4 +1077,21 @@ describe('Fargate containers', () => { }), })).toThrow('Readonly root filesystem is not possible on Windows; write access is required for registry & system processes to run inside the container'); }); + + test('readonlyRootFilesystem is undefined with Windows family', () => { + // WHEN + new EcsJobDefinition(stack, 'ECSJobDefn', { + container: new EcsFargateContainerDefinition(stack, 'EcsFargateContainer', { + ...defaultContainerProps, + fargateOperatingSystemFamily: ecs.OperatingSystemFamily.WINDOWS_SERVER_2004_CORE, + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Batch::JobDefinition', { + ContainerProperties: { + ReadonlyRootFilesystem: Match.absent(), + }, + }); + }); }); From 7a655204054156da779ef1acc9181ad6603d7e67 Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Thu, 22 Feb 2024 16:33:46 -0500 Subject: [PATCH 3/6] move function to OperatingSystemFamily class --- .../aws-batch/lib/ecs-container-definition.ts | 11 ++--------- .../aws-cdk-lib/aws-ecs/lib/runtime-platform.ts | 14 +++++++++++++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts index 1d0365ec20b29..48fd717bace5e 100644 --- a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts +++ b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts @@ -703,13 +703,6 @@ abstract class EcsContainerDefinitionBase extends Construct implements IEcsConta }; } - protected isWindows(operatingSystemFamily?: string): boolean { - if (operatingSystemFamily?.toLowerCase().includes('windows')) { - return true; - } - return false; - } - public addVolume(volume: EcsVolume): void { this.volumes.push(volume); } @@ -1064,7 +1057,7 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im this.fargateCpuArchitecture = props.fargateCpuArchitecture; this.fargateOperatingSystemFamily = props.fargateOperatingSystemFamily; - if (this.isWindows(this.fargateOperatingSystemFamily?._operatingSystemFamily) && this.readonlyRootFilesystem) { + if (this.fargateOperatingSystemFamily?.isWindows() && this.readonlyRootFilesystem) { // see https://kubernetes.io/docs/concepts/windows/intro/ throw new Error('Readonly root filesystem is not possible on Windows; write access is required for registry & system processes to run inside the container'); } @@ -1103,7 +1096,7 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im }; // readonlyRootFilesystem isn't applicable to Windows, see https://kubernetes.io/docs/concepts/windows/intro/ - if (this.isWindows(operatingSystemFamily)) { + if (this.fargateOperatingSystemFamily?.isWindows()) { containerDef.readonlyRootFilesystem = undefined; } diff --git a/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts b/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts index 37d760c62e657..e9df3603872e1 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts @@ -88,6 +88,17 @@ export class OperatingSystemFamily { * @param _operatingSystemFamily The operating system family. */ private constructor(public readonly _operatingSystemFamily: string) { } + + /** + * Returns true if the operating system family is Windows + */ + public isWindows(): boolean { + if (this._operatingSystemFamily?.toLowerCase().includes('windows')) { + return true; + } + return false; + } + } /** @@ -107,4 +118,5 @@ export interface RuntimePlatform { * @default - Undefined. */ readonly operatingSystemFamily?: OperatingSystemFamily; -} \ No newline at end of file +} + From b38b4b0b07d20b225e9ad922a546082cf12c22f5 Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Thu, 22 Feb 2024 16:35:05 -0500 Subject: [PATCH 4/6] remove constant --- .../aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts index 48fd717bace5e..2253cb7d4868c 100644 --- a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts +++ b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts @@ -1076,8 +1076,6 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im * @internal */ public _renderContainerDefinition(): CfnJobDefinition.ContainerPropertiesProperty { - const operatingSystemFamily = this.fargateOperatingSystemFamily?._operatingSystemFamily; - let containerDef = { ...super._renderContainerDefinition(), ephemeralStorage: this.ephemeralStorageSize? { @@ -1091,7 +1089,7 @@ export class EcsFargateContainerDefinition extends EcsContainerDefinitionBase im }, runtimePlatform: { cpuArchitecture: this.fargateCpuArchitecture?._cpuArchitecture, - operatingSystemFamily, + operatingSystemFamily: this.fargateOperatingSystemFamily?._operatingSystemFamily, }, }; From 83bef464434c17b839418f8d7c1c90aec09f5e3d Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Thu, 22 Feb 2024 16:35:49 -0500 Subject: [PATCH 5/6] extra newline --- packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts b/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts index e9df3603872e1..04f9cbb6c2c67 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts @@ -119,4 +119,3 @@ export interface RuntimePlatform { */ readonly operatingSystemFamily?: OperatingSystemFamily; } - From 677090fff9bf8942b9529072357ea71c97b4a3de Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Fri, 1 Mar 2024 12:51:01 -0700 Subject: [PATCH 6/6] use ternary --- packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts b/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts index 04f9cbb6c2c67..250e64a1f9ca4 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/runtime-platform.ts @@ -93,12 +93,8 @@ export class OperatingSystemFamily { * Returns true if the operating system family is Windows */ public isWindows(): boolean { - if (this._operatingSystemFamily?.toLowerCase().includes('windows')) { - return true; - } - return false; + return this._operatingSystemFamily?.toLowerCase().startsWith('windows') ? true : false; } - } /**