diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.assets.json new file mode 100644 index 0000000000000..620f3ee112960 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.assets.json @@ -0,0 +1,20 @@ +{ + "version": "41.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703 Template", + "source": { + "path": "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.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.cluster-windows-core-ami.js.snapshot/ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.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.cluster-windows-core-ami.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/cdk.out new file mode 100644 index 0000000000000..188478b55560e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"41.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/integ-ecs-windows-core-ami.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/integ-ecs-windows-core-ami.assets.json new file mode 100644 index 0000000000000..ba28907a4c915 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/integ-ecs-windows-core-ami.assets.json @@ -0,0 +1,20 @@ +{ + "version": "41.0.0", + "files": { + "7ad57b3d8e07bb3f7b1fc59ad03f087e1748b1f05be63e40d2d810cfe02bcf75": { + "displayName": "integ-ecs-windows-core-ami Template", + "source": { + "path": "integ-ecs-windows-core-ami.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "7ad57b3d8e07bb3f7b1fc59ad03f087e1748b1f05be63e40d2d810cfe02bcf75.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.cluster-windows-core-ami.js.snapshot/integ-ecs-windows-core-ami.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/integ-ecs-windows-core-ami.template.json new file mode 100644 index 0000000000000..587ab77e12db8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/integ-ecs-windows-core-ami.template.json @@ -0,0 +1,1495 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet1RouteTableAssociation97140677" + ] + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.64.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "VpcPublicSubnet2DefaultRoute97F91067", + "VpcPublicSubnet2RouteTableAssociationDD5762D8" + ] + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.192.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ClusterEB0386A7": { + "Type": "AWS::ECS::Cluster" + }, + "Cluster3DA9CCBA": { + "Type": "AWS::ECS::ClusterCapacityProviderAssociations", + "Properties": { + "CapacityProviders": [ + { + "Ref": "EC2CapacityProvider2022CoreA6E67593" + }, + { + "Ref": "EC2CapacityProvider2019Core6C94ECB3" + } + ], + "Cluster": { + "Ref": "ClusterEB0386A7" + }, + "DefaultCapacityProviderStrategy": [] + } + }, + "ASGWin2022CoreInstanceSecurityGroup9B150272": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ASGWin2022CoreInstanceRole260B30CC": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core" + } + ] + } + }, + "ASGWin2022CoreInstanceRoleDefaultPolicyAFE03968": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecs:DeregisterContainerInstance", + "ecs:RegisterContainerInstance", + "ecs:Submit*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "ClusterEB0386A7", + "Arn" + ] + } + }, + { + "Action": [ + "ecs:Poll", + "ecs:StartTelemetrySession" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "ClusterEB0386A7", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ASGWin2022CoreInstanceRoleDefaultPolicyAFE03968", + "Roles": [ + { + "Ref": "ASGWin2022CoreInstanceRole260B30CC" + } + ] + } + }, + "ASGWin2022CoreInstanceProfile19561E87": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "ASGWin2022CoreInstanceRole260B30CC" + } + ] + } + }, + "ASGWin2022CoreLaunchTemplateEC9D9176": { + "Type": "AWS::EC2::LaunchTemplate", + "Properties": { + "LaunchTemplateData": { + "IamInstanceProfile": { + "Arn": { + "Fn::GetAtt": [ + "ASGWin2022CoreInstanceProfile19561E87", + "Arn" + ] + } + }, + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiwindowslatestWindowsServer2022EnglishCoreECSOptimizedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "t2.micro", + "Monitoring": { + "Enabled": false + }, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ASGWin2022CoreInstanceSecurityGroup9B150272", + "GroupId" + ] + } + ], + "TagSpecifications": [ + { + "ResourceType": "instance", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate" + } + ] + }, + { + "ResourceType": "volume", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate" + } + ] + } + ], + "UserData": { + "Fn::Base64": { + "Fn::Join": [ + "", + [ + "Remove-Item -Recurse C:\\ProgramData\\Amazon\\ECS\\Cache\nImport-Module ECSTools\n[Environment]::SetEnvironmentVariable(\"ECS_CLUSTER\", \"", + { + "Ref": "ClusterEB0386A7" + }, + "\", \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE\", \"true\", \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_AVAILABLE_LOGGING_DRIVERS\", '[\"json-file\",\"awslogs\"]', \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_ENABLE_TASK_IAM_ROLE\", \"true\", \"Machine\")\nInitialize-ECSAgent -Cluster '", + { + "Ref": "ClusterEB0386A7" + }, + "' -EnableTaskIAMRole" + ] + ] + } + } + }, + "TagSpecifications": [ + { + "ResourceType": "launch-template", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate" + } + ] + } + ] + }, + "DependsOn": [ + "ASGWin2022CoreInstanceRoleDefaultPolicyAFE03968", + "ASGWin2022CoreInstanceRole260B30CC" + ] + }, + "ASGWin2022CoreASGBB924878": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "LaunchTemplate": { + "LaunchTemplateId": { + "Ref": "ASGWin2022CoreLaunchTemplateEC9D9176" + }, + "Version": { + "Fn::GetAtt": [ + "ASGWin2022CoreLaunchTemplateEC9D9176", + "LatestVersionNumber" + ] + } + }, + "MaxSize": "1", + "MinSize": "0", + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + }, + "UpdatePolicy": { + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + }, + "ASGWin2022CoreDrainECSHookFunctionServiceRoleDEB0FB03": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core" + } + ] + } + }, + "ASGWin2022CoreDrainECSHookFunctionServiceRoleDefaultPolicy91DA5587": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:DescribeHosts", + "ec2:DescribeInstanceAttribute", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInstances" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "autoscaling:CompleteLifecycleAction", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":autoscaling:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":autoScalingGroup:*:autoScalingGroupName/", + { + "Ref": "ASGWin2022CoreASGBB924878" + } + ] + ] + } + }, + { + "Action": [ + "ecs:DescribeContainerInstances", + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "ClusterEB0386A7", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecs:ListContainerInstances", + "ecs:SubmitContainerStateChange", + "ecs:SubmitTaskStateChange" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "ClusterEB0386A7", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ASGWin2022CoreDrainECSHookFunctionServiceRoleDefaultPolicy91DA5587", + "Roles": [ + { + "Ref": "ASGWin2022CoreDrainECSHookFunctionServiceRoleDEB0FB03" + } + ] + } + }, + "ASGWin2022CoreDrainECSHookFunction9D903E21": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(dict(event, ResponseURL='...')))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(dict(event, ResponseURL='...')))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n\n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n\n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n\n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + }, + "Environment": { + "Variables": { + "CLUSTER": { + "Ref": "ClusterEB0386A7" + } + } + }, + "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "ASGWin2022CoreDrainECSHookFunctionServiceRoleDEB0FB03", + "Arn" + ] + }, + "Runtime": "python3.9", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core" + } + ], + "Timeout": 310 + }, + "DependsOn": [ + "ASGWin2022CoreDrainECSHookFunctionServiceRoleDefaultPolicy91DA5587", + "ASGWin2022CoreDrainECSHookFunctionServiceRoleDEB0FB03" + ] + }, + "ASGWin2022CoreDrainECSHookFunctionAllowInvokeintegecswindowscoreamiASGWin2022CoreLifecycleHookDrainHookTopicE3196F76BF426C03": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ASGWin2022CoreDrainECSHookFunction9D903E21", + "Arn" + ] + }, + "Principal": "sns.amazonaws.com", + "SourceArn": { + "Ref": "ASGWin2022CoreLifecycleHookDrainHookTopicFA049579" + } + } + }, + "ASGWin2022CoreDrainECSHookFunctionTopic1FAAFBDC": { + "Type": "AWS::SNS::Subscription", + "Properties": { + "Endpoint": { + "Fn::GetAtt": [ + "ASGWin2022CoreDrainECSHookFunction9D903E21", + "Arn" + ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "ASGWin2022CoreLifecycleHookDrainHookTopicFA049579" + } + } + }, + "ASGWin2022CoreLifecycleHookDrainHookTopicFA049579": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core" + } + ] + } + }, + "ASGWin2022CoreLifecycleHookDrainHookRole067A0289": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "autoscaling.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2022Core" + } + ] + } + }, + "ASGWin2022CoreLifecycleHookDrainHookRoleDefaultPolicyEC5E58D9": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": { + "Ref": "ASGWin2022CoreLifecycleHookDrainHookTopicFA049579" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ASGWin2022CoreLifecycleHookDrainHookRoleDefaultPolicyEC5E58D9", + "Roles": [ + { + "Ref": "ASGWin2022CoreLifecycleHookDrainHookRole067A0289" + } + ] + } + }, + "ASGWin2022CoreLifecycleHookDrainHook5EDDCA84": { + "Type": "AWS::AutoScaling::LifecycleHook", + "Properties": { + "AutoScalingGroupName": { + "Ref": "ASGWin2022CoreASGBB924878" + }, + "DefaultResult": "CONTINUE", + "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", + "NotificationTargetARN": { + "Ref": "ASGWin2022CoreLifecycleHookDrainHookTopicFA049579" + }, + "RoleARN": { + "Fn::GetAtt": [ + "ASGWin2022CoreLifecycleHookDrainHookRole067A0289", + "Arn" + ] + } + }, + "DependsOn": [ + "ASGWin2022CoreLifecycleHookDrainHookRoleDefaultPolicyEC5E58D9", + "ASGWin2022CoreLifecycleHookDrainHookRole067A0289" + ] + }, + "EC2CapacityProvider2022CoreA6E67593": { + "Type": "AWS::ECS::CapacityProvider", + "Properties": { + "AutoScalingGroupProvider": { + "AutoScalingGroupArn": { + "Ref": "ASGWin2022CoreASGBB924878" + }, + "ManagedScaling": { + "Status": "ENABLED", + "TargetCapacity": 100 + }, + "ManagedTerminationProtection": "DISABLED" + } + } + }, + "ASGWin2019CoreInstanceSecurityGroup98D7D0D0": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ASGWin2019CoreInstanceRole789AFEC5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core" + } + ] + } + }, + "ASGWin2019CoreInstanceRoleDefaultPolicy93C292B8": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ecs:DeregisterContainerInstance", + "ecs:RegisterContainerInstance", + "ecs:Submit*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "ClusterEB0386A7", + "Arn" + ] + } + }, + { + "Action": [ + "ecs:Poll", + "ecs:StartTelemetrySession" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "ClusterEB0386A7", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecr:GetAuthorizationToken", + "ecs:DiscoverPollEndpoint", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ASGWin2019CoreInstanceRoleDefaultPolicy93C292B8", + "Roles": [ + { + "Ref": "ASGWin2019CoreInstanceRole789AFEC5" + } + ] + } + }, + "ASGWin2019CoreInstanceProfileBF14CDCB": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "ASGWin2019CoreInstanceRole789AFEC5" + } + ] + } + }, + "ASGWin2019CoreLaunchTemplate9CDB8014": { + "Type": "AWS::EC2::LaunchTemplate", + "Properties": { + "LaunchTemplateData": { + "IamInstanceProfile": { + "Arn": { + "Fn::GetAtt": [ + "ASGWin2019CoreInstanceProfileBF14CDCB", + "Arn" + ] + } + }, + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishCoreECSOptimizedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "t2.micro", + "Monitoring": { + "Enabled": false + }, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ASGWin2019CoreInstanceSecurityGroup98D7D0D0", + "GroupId" + ] + } + ], + "TagSpecifications": [ + { + "ResourceType": "instance", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate" + } + ] + }, + { + "ResourceType": "volume", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate" + } + ] + } + ], + "UserData": { + "Fn::Base64": { + "Fn::Join": [ + "", + [ + "Remove-Item -Recurse C:\\ProgramData\\Amazon\\ECS\\Cache\nImport-Module ECSTools\n[Environment]::SetEnvironmentVariable(\"ECS_CLUSTER\", \"", + { + "Ref": "ClusterEB0386A7" + }, + "\", \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE\", \"true\", \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_AVAILABLE_LOGGING_DRIVERS\", '[\"json-file\",\"awslogs\"]', \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_ENABLE_TASK_IAM_ROLE\", \"true\", \"Machine\")\nInitialize-ECSAgent -Cluster '", + { + "Ref": "ClusterEB0386A7" + }, + "' -EnableTaskIAMRole" + ] + ] + } + } + }, + "TagSpecifications": [ + { + "ResourceType": "launch-template", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate" + } + ] + } + ] + }, + "DependsOn": [ + "ASGWin2019CoreInstanceRoleDefaultPolicy93C292B8", + "ASGWin2019CoreInstanceRole789AFEC5" + ] + }, + "ASGWin2019CoreASG09FBC80E": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "LaunchTemplate": { + "LaunchTemplateId": { + "Ref": "ASGWin2019CoreLaunchTemplate9CDB8014" + }, + "Version": { + "Fn::GetAtt": [ + "ASGWin2019CoreLaunchTemplate9CDB8014", + "LatestVersionNumber" + ] + } + }, + "MaxSize": "1", + "MinSize": "0", + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + }, + "UpdatePolicy": { + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } + }, + "ASGWin2019CoreDrainECSHookFunctionServiceRole74692A98": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core" + } + ] + } + }, + "ASGWin2019CoreDrainECSHookFunctionServiceRoleDefaultPolicy852E2B97": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ec2:DescribeHosts", + "ec2:DescribeInstanceAttribute", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInstances" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "autoscaling:CompleteLifecycleAction", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":autoscaling:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":autoScalingGroup:*:autoScalingGroupName/", + { + "Ref": "ASGWin2019CoreASG09FBC80E" + } + ] + ] + } + }, + { + "Action": [ + "ecs:DescribeContainerInstances", + "ecs:DescribeTasks", + "ecs:ListTasks", + "ecs:UpdateContainerInstancesState" + ], + "Condition": { + "ArnEquals": { + "ecs:cluster": { + "Fn::GetAtt": [ + "ClusterEB0386A7", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecs:ListContainerInstances", + "ecs:SubmitContainerStateChange", + "ecs:SubmitTaskStateChange" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "ClusterEB0386A7", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ASGWin2019CoreDrainECSHookFunctionServiceRoleDefaultPolicy852E2B97", + "Roles": [ + { + "Ref": "ASGWin2019CoreDrainECSHookFunctionServiceRole74692A98" + } + ] + } + }, + "ASGWin2019CoreDrainECSHookFunction17A7DCA1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(dict(event, ResponseURL='...')))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(dict(event, ResponseURL='...')))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n\n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n\n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n\n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n" + }, + "Environment": { + "Variables": { + "CLUSTER": { + "Ref": "ClusterEB0386A7" + } + } + }, + "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "ASGWin2019CoreDrainECSHookFunctionServiceRole74692A98", + "Arn" + ] + }, + "Runtime": "python3.9", + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core" + } + ], + "Timeout": 310 + }, + "DependsOn": [ + "ASGWin2019CoreDrainECSHookFunctionServiceRoleDefaultPolicy852E2B97", + "ASGWin2019CoreDrainECSHookFunctionServiceRole74692A98" + ] + }, + "ASGWin2019CoreDrainECSHookFunctionAllowInvokeintegecswindowscoreamiASGWin2019CoreLifecycleHookDrainHookTopic3026395C39011247": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Fn::GetAtt": [ + "ASGWin2019CoreDrainECSHookFunction17A7DCA1", + "Arn" + ] + }, + "Principal": "sns.amazonaws.com", + "SourceArn": { + "Ref": "ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1" + } + } + }, + "ASGWin2019CoreDrainECSHookFunctionTopicA397387A": { + "Type": "AWS::SNS::Subscription", + "Properties": { + "Endpoint": { + "Fn::GetAtt": [ + "ASGWin2019CoreDrainECSHookFunction17A7DCA1", + "Arn" + ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1" + } + } + }, + "ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1": { + "Type": "AWS::SNS::Topic", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core" + } + ] + } + }, + "ASGWin2019CoreLifecycleHookDrainHookRole0BD06247": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "autoscaling.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-ecs-windows-core-ami/ASG-Win2019Core" + } + ] + } + }, + "ASGWin2019CoreLifecycleHookDrainHookRoleDefaultPolicy2CBAED41": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sns:Publish", + "Effect": "Allow", + "Resource": { + "Ref": "ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ASGWin2019CoreLifecycleHookDrainHookRoleDefaultPolicy2CBAED41", + "Roles": [ + { + "Ref": "ASGWin2019CoreLifecycleHookDrainHookRole0BD06247" + } + ] + } + }, + "ASGWin2019CoreLifecycleHookDrainHook55A813D4": { + "Type": "AWS::AutoScaling::LifecycleHook", + "Properties": { + "AutoScalingGroupName": { + "Ref": "ASGWin2019CoreASG09FBC80E" + }, + "DefaultResult": "CONTINUE", + "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", + "NotificationTargetARN": { + "Ref": "ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1" + }, + "RoleARN": { + "Fn::GetAtt": [ + "ASGWin2019CoreLifecycleHookDrainHookRole0BD06247", + "Arn" + ] + } + }, + "DependsOn": [ + "ASGWin2019CoreLifecycleHookDrainHookRoleDefaultPolicy2CBAED41", + "ASGWin2019CoreLifecycleHookDrainHookRole0BD06247" + ] + }, + "EC2CapacityProvider2019Core6C94ECB3": { + "Type": "AWS::ECS::CapacityProvider", + "Properties": { + "AutoScalingGroupProvider": { + "AutoScalingGroupArn": { + "Ref": "ASGWin2019CoreASG09FBC80E" + }, + "ManagedScaling": { + "Status": "ENABLED", + "TargetCapacity": 100 + }, + "ManagedTerminationProtection": "DISABLED" + } + } + } + }, + "Parameters": { + "SsmParameterValueawsserviceamiwindowslatestWindowsServer2022EnglishCoreECSOptimizedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-windows-latest/Windows_Server-2022-English-Core-ECS_Optimized/image_id" + }, + "SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishCoreECSOptimizedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-windows-latest/Windows_Server-2019-English-Core-ECS_Optimized/image_id" + }, + "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.cluster-windows-core-ami.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/integ.json new file mode 100644 index 0000000000000..cc856cd101783 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "41.0.0", + "testCases": { + "ClusterWindowsCoreAmi/DefaultTest": { + "stacks": [ + "integ-ecs-windows-core-ami" + ], + "assertionStack": "ClusterWindowsCoreAmi/DefaultTest/DeployAssert", + "assertionStackName": "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/manifest.json new file mode 100644 index 0000000000000..e94fde4bfa6aa --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/manifest.json @@ -0,0 +1,1070 @@ +{ + "version": "42.0.0", + "artifacts": { + "integ-ecs-windows-core-ami.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-ecs-windows-core-ami.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-ecs-windows-core-ami": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-ecs-windows-core-ami.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}/7ad57b3d8e07bb3f7b1fc59ad03f087e1748b1f05be63e40d2d810cfe02bcf75.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-ecs-windows-core-ami.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": [ + "integ-ecs-windows-core-ami.assets" + ], + "metadata": { + "/integ-ecs-windows-core-ami/Vpc": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/Vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Vpc8378EB38" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet1": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1Subnet5C2D37C4" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1RouteTable6C95E38E" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1RouteTableAssociation97140677" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1DefaultRoute3DA9E72A" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet1/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1EIPD7E02669" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet1/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet1NATGateway4D7517AA" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet2": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2Subnet691E08A3" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2RouteTable94F7E489" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2RouteTableAssociationDD5762D8" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2DefaultRoute97F91067" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet2/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2EIP3C605A87" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PublicSubnet2/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPublicSubnet2NATGateway9182C01D" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet1": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet1Subnet536B997A" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet1RouteTableB2C5B500" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet1RouteTableAssociation70C59FA6" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet1DefaultRouteBE02A9ED" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet2": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet2Subnet3788AAA1" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet2RouteTableA678073B" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet2RouteTableAssociationA89CAD56" + } + ], + "/integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcPrivateSubnet2DefaultRoute060D2087" + } + ], + "/integ-ecs-windows-core-ami/Vpc/IGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcIGWD7BA715C" + } + ], + "/integ-ecs-windows-core-ami/Vpc/VPCGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcVPCGWBF912B6E" + } + ], + "/integ-ecs-windows-core-ami/Cluster": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:warning", + "data": "Blocking container accessing instance role is not supported. See https://github.com/aws/aws-cdk/discussions/32609 [ack: @aws-cdk/aws-ecs:deprecatedImdsBlocking]" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterEB0386A7" + } + ], + "/integ-ecs-windows-core-ami/Cluster/Cluster": [ + { + "type": "aws:cdk:logicalId", + "data": "Cluster3DA9CCBA" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceSecurityGroup": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceSecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreInstanceSecurityGroup9B150272" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole/ImportInstanceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreInstanceRole260B30CC" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreInstanceRoleDefaultPolicyAFE03968" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceProfile": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreInstanceProfile19561E87" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreLaunchTemplateEC9D9176" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/ASG": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreASGBB924878" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreDrainECSHookFunctionServiceRoleDEB0FB03" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreDrainECSHookFunctionServiceRoleDefaultPolicy91DA5587" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreDrainECSHookFunction9D903E21" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/AllowInvoke:integecswindowscoreamiASGWin2022CoreLifecycleHookDrainHookTopicE3196F76": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreDrainECSHookFunctionAllowInvokeintegecswindowscoreamiASGWin2022CoreLifecycleHookDrainHookTopicE3196F76BF426C03" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/Topic": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/Topic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreDrainECSHookFunctionTopic1FAAFBDC" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Topic": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Topic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreLifecycleHookDrainHookTopicFA049579" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreLifecycleHookDrainHookRole067A0289" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreLifecycleHookDrainHookRoleDefaultPolicyEC5E58D9" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2022CoreLifecycleHookDrainHook5EDDCA84" + } + ], + "/integ-ecs-windows-core-ami/SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2022-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter": [ + { + "type": "aws:cdk:logicalId", + "data": "SsmParameterValueawsserviceamiwindowslatestWindowsServer2022EnglishCoreECSOptimizedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + } + ], + "/integ-ecs-windows-core-ami/EC2CapacityProvider2022Core/EC2CapacityProvider2022Core": [ + { + "type": "aws:cdk:logicalId", + "data": "EC2CapacityProvider2022CoreA6E67593" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceSecurityGroup": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceSecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreInstanceSecurityGroup98D7D0D0" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole/ImportInstanceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreInstanceRole789AFEC5" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreInstanceRoleDefaultPolicy93C292B8" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceProfile": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreInstanceProfileBF14CDCB" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreLaunchTemplate9CDB8014" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/ASG": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreASG09FBC80E" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreDrainECSHookFunctionServiceRole74692A98" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreDrainECSHookFunctionServiceRoleDefaultPolicy852E2B97" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreDrainECSHookFunction17A7DCA1" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/AllowInvoke:integecswindowscoreamiASGWin2019CoreLifecycleHookDrainHookTopic3026395C": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreDrainECSHookFunctionAllowInvokeintegecswindowscoreamiASGWin2019CoreLifecycleHookDrainHookTopic3026395C39011247" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/Topic": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/Topic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreDrainECSHookFunctionTopicA397387A" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Topic": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Topic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role/ImportRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreLifecycleHookDrainHookRole0BD06247" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreLifecycleHookDrainHookRoleDefaultPolicy2CBAED41" + } + ], + "/integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGWin2019CoreLifecycleHookDrainHook55A813D4" + } + ], + "/integ-ecs-windows-core-ami/SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2019-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter": [ + { + "type": "aws:cdk:logicalId", + "data": "SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishCoreECSOptimizedimageidC96584B6F00A464EAD1953AFF4B05118Parameter" + } + ], + "/integ-ecs-windows-core-ami/EC2CapacityProvider2019Core/EC2CapacityProvider2019Core": [ + { + "type": "aws:cdk:logicalId", + "data": "EC2CapacityProvider2019Core6C94ECB3" + } + ], + "/integ-ecs-windows-core-ami/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-ecs-windows-core-ami/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-ecs-windows-core-ami" + }, + "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.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": [ + "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.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": [ + "ClusterWindowsCoreAmiDefaultTestDeployAssertCCAFA703.assets" + ], + "metadata": { + "/ClusterWindowsCoreAmi/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/ClusterWindowsCoreAmi/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "ClusterWindowsCoreAmi/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + }, + "minimumCliVersion": "2.1006.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/tree.json new file mode 100644 index 0000000000000..109f891c2e999 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","children":{"integ-ecs-windows-core-ami":{"id":"integ-ecs-windows-core-ami","path":"integ-ecs-windows-core-ami","children":{"Vpc":{"id":"Vpc","path":"integ-ecs-windows-core-ami/Vpc","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/Vpc/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::VPC","aws:cdk:cloudformation:props":{"cidrBlock":"10.0.0.0/16","enableDnsHostnames":true,"enableDnsSupport":true,"instanceTenancy":"default","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"PublicSubnet1":{"id":"PublicSubnet1","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1","children":{"Subnet":{"id":"Subnet","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1/Subnet","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::Subnet","aws:cdk:cloudformation:props":{"availabilityZone":{"Fn::Select":[0,{"Fn::GetAZs":""}]},"cidrBlock":"10.0.0.0/18","mapPublicIpOnLaunch":true,"tags":[{"key":"aws-cdk:subnet-name","value":"Public"},{"key":"aws-cdk:subnet-type","value":"Public"},{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Acl":{"id":"Acl","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1/Acl","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"RouteTable":{"id":"RouteTable","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1/RouteTable","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::RouteTable","aws:cdk:cloudformation:props":{"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"RouteTableAssociation":{"id":"RouteTableAssociation","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1/RouteTableAssociation","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::SubnetRouteTableAssociation","aws:cdk:cloudformation:props":{"routeTableId":{"Ref":"VpcPublicSubnet1RouteTable6C95E38E"},"subnetId":{"Ref":"VpcPublicSubnet1Subnet5C2D37C4"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultRoute":{"id":"DefaultRoute","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1/DefaultRoute","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::Route","aws:cdk:cloudformation:props":{"destinationCidrBlock":"0.0.0.0/0","gatewayId":{"Ref":"VpcIGWD7BA715C"},"routeTableId":{"Ref":"VpcPublicSubnet1RouteTable6C95E38E"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"EIP":{"id":"EIP","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1/EIP","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::EIP","aws:cdk:cloudformation:props":{"domain":"vpc","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"NATGateway":{"id":"NATGateway","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1/NATGateway","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::NatGateway","aws:cdk:cloudformation:props":{"allocationId":{"Fn::GetAtt":["VpcPublicSubnet1EIPD7E02669","AllocationId"]},"subnetId":{"Ref":"VpcPublicSubnet1Subnet5C2D37C4"},"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PublicSubnet1"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}},"PublicSubnet2":{"id":"PublicSubnet2","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2","children":{"Subnet":{"id":"Subnet","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2/Subnet","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::Subnet","aws:cdk:cloudformation:props":{"availabilityZone":{"Fn::Select":[1,{"Fn::GetAZs":""}]},"cidrBlock":"10.0.64.0/18","mapPublicIpOnLaunch":true,"tags":[{"key":"aws-cdk:subnet-name","value":"Public"},{"key":"aws-cdk:subnet-type","value":"Public"},{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Acl":{"id":"Acl","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2/Acl","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"RouteTable":{"id":"RouteTable","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2/RouteTable","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::RouteTable","aws:cdk:cloudformation:props":{"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"RouteTableAssociation":{"id":"RouteTableAssociation","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2/RouteTableAssociation","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::SubnetRouteTableAssociation","aws:cdk:cloudformation:props":{"routeTableId":{"Ref":"VpcPublicSubnet2RouteTable94F7E489"},"subnetId":{"Ref":"VpcPublicSubnet2Subnet691E08A3"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultRoute":{"id":"DefaultRoute","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2/DefaultRoute","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::Route","aws:cdk:cloudformation:props":{"destinationCidrBlock":"0.0.0.0/0","gatewayId":{"Ref":"VpcIGWD7BA715C"},"routeTableId":{"Ref":"VpcPublicSubnet2RouteTable94F7E489"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"EIP":{"id":"EIP","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2/EIP","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::EIP","aws:cdk:cloudformation:props":{"domain":"vpc","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"NATGateway":{"id":"NATGateway","path":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2/NATGateway","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::NatGateway","aws:cdk:cloudformation:props":{"allocationId":{"Fn::GetAtt":["VpcPublicSubnet2EIP3C605A87","AllocationId"]},"subnetId":{"Ref":"VpcPublicSubnet2Subnet691E08A3"},"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PublicSubnet2"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}},"PrivateSubnet1":{"id":"PrivateSubnet1","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet1","children":{"Subnet":{"id":"Subnet","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/Subnet","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::Subnet","aws:cdk:cloudformation:props":{"availabilityZone":{"Fn::Select":[0,{"Fn::GetAZs":""}]},"cidrBlock":"10.0.128.0/18","mapPublicIpOnLaunch":false,"tags":[{"key":"aws-cdk:subnet-name","value":"Private"},{"key":"aws-cdk:subnet-type","value":"Private"},{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet1"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Acl":{"id":"Acl","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/Acl","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"RouteTable":{"id":"RouteTable","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/RouteTable","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::RouteTable","aws:cdk:cloudformation:props":{"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet1"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"RouteTableAssociation":{"id":"RouteTableAssociation","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/RouteTableAssociation","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::SubnetRouteTableAssociation","aws:cdk:cloudformation:props":{"routeTableId":{"Ref":"VpcPrivateSubnet1RouteTableB2C5B500"},"subnetId":{"Ref":"VpcPrivateSubnet1Subnet536B997A"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultRoute":{"id":"DefaultRoute","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet1/DefaultRoute","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::Route","aws:cdk:cloudformation:props":{"destinationCidrBlock":"0.0.0.0/0","natGatewayId":{"Ref":"VpcPublicSubnet1NATGateway4D7517AA"},"routeTableId":{"Ref":"VpcPrivateSubnet1RouteTableB2C5B500"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*"]}},"PrivateSubnet2":{"id":"PrivateSubnet2","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet2","children":{"Subnet":{"id":"Subnet","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/Subnet","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::Subnet","aws:cdk:cloudformation:props":{"availabilityZone":{"Fn::Select":[1,{"Fn::GetAZs":""}]},"cidrBlock":"10.0.192.0/18","mapPublicIpOnLaunch":false,"tags":[{"key":"aws-cdk:subnet-name","value":"Private"},{"key":"aws-cdk:subnet-type","value":"Private"},{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet2"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Acl":{"id":"Acl","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/Acl","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"RouteTable":{"id":"RouteTable","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/RouteTable","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::RouteTable","aws:cdk:cloudformation:props":{"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet2"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"RouteTableAssociation":{"id":"RouteTableAssociation","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/RouteTableAssociation","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::SubnetRouteTableAssociation","aws:cdk:cloudformation:props":{"routeTableId":{"Ref":"VpcPrivateSubnet2RouteTableA678073B"},"subnetId":{"Ref":"VpcPrivateSubnet2Subnet3788AAA1"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultRoute":{"id":"DefaultRoute","path":"integ-ecs-windows-core-ami/Vpc/PrivateSubnet2/DefaultRoute","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::Route","aws:cdk:cloudformation:props":{"destinationCidrBlock":"0.0.0.0/0","natGatewayId":{"Ref":"VpcPublicSubnet2NATGateway9182C01D"},"routeTableId":{"Ref":"VpcPrivateSubnet2RouteTableA678073B"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*"]}},"IGW":{"id":"IGW","path":"integ-ecs-windows-core-ami/Vpc/IGW","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::InternetGateway","aws:cdk:cloudformation:props":{"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/Vpc"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"VPCGW":{"id":"VPCGW","path":"integ-ecs-windows-core-ami/Vpc/VPCGW","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::VPCGatewayAttachment","aws:cdk:cloudformation:props":{"internetGatewayId":{"Ref":"VpcIGWD7BA715C"},"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Cluster":{"id":"Cluster","path":"integ-ecs-windows-core-ami/Cluster","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/Cluster/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::ECS::Cluster","aws:cdk:cloudformation:props":{}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Cluster":{"id":"Cluster","path":"integ-ecs-windows-core-ami/Cluster/Cluster","attributes":{"aws:cdk:cloudformation:type":"AWS::ECS::ClusterCapacityProviderAssociations","aws:cdk:cloudformation:props":{"capacityProviders":[{"Ref":"EC2CapacityProvider2022CoreA6E67593"},{"Ref":"EC2CapacityProvider2019Core6C94ECB3"}],"cluster":{"Ref":"ClusterEB0386A7"},"defaultCapacityProviderStrategy":[]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*"]}},"ASG-Win2022Core":{"id":"ASG-Win2022Core","path":"integ-ecs-windows-core-ami/ASG-Win2022Core","children":{"InstanceSecurityGroup":{"id":"InstanceSecurityGroup","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceSecurityGroup","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceSecurityGroup/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::SecurityGroup","aws:cdk:cloudformation:props":{"groupDescription":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceSecurityGroup","securityGroupEgress":[{"cidrIp":"0.0.0.0/0","description":"Allow all outbound traffic by default","ipProtocol":"-1"}],"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"InstanceRole":{"id":"InstanceRole","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole","children":{"ImportInstanceRole":{"id":"ImportInstanceRole","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole/ImportInstanceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"}}],"Version":"2012-10-17"},"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceRole/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["ecs:DeregisterContainerInstance","ecs:RegisterContainerInstance","ecs:Submit*"],"Effect":"Allow","Resource":{"Fn::GetAtt":["ClusterEB0386A7","Arn"]}},{"Action":["ecs:Poll","ecs:StartTelemetrySession"],"Condition":{"ArnEquals":{"ecs:cluster":{"Fn::GetAtt":["ClusterEB0386A7","Arn"]}}},"Effect":"Allow","Resource":"*"},{"Action":["ecr:GetAuthorizationToken","ecs:DiscoverPollEndpoint","logs:CreateLogStream","logs:PutLogEvents"],"Effect":"Allow","Resource":"*"}],"Version":"2012-10-17"},"policyName":"ASGWin2022CoreInstanceRoleDefaultPolicyAFE03968","roles":[{"Ref":"ASGWin2022CoreInstanceRole260B30CC"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*"]}},"InstanceProfile":{"id":"InstanceProfile","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/InstanceProfile","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::InstanceProfile","aws:cdk:cloudformation:props":{"roles":[{"Ref":"ASGWin2022CoreInstanceRole260B30CC"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"ImportedInstanceProfile":{"id":"ImportedInstanceProfile","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/ImportedInstanceProfile","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"LaunchTemplate":{"id":"LaunchTemplate","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::LaunchTemplate","aws:cdk:cloudformation:props":{"launchTemplateData":{"iamInstanceProfile":{"arn":{"Fn::GetAtt":["ASGWin2022CoreInstanceProfile19561E87","Arn"]}},"imageId":{"Ref":"SsmParameterValueawsserviceamiwindowslatestWindowsServer2022EnglishCoreECSOptimizedimageidC96584B6F00A464EAD1953AFF4B05118Parameter"},"instanceType":"t2.micro","monitoring":{"enabled":false},"securityGroupIds":[{"Fn::GetAtt":["ASGWin2022CoreInstanceSecurityGroup9B150272","GroupId"]}],"tagSpecifications":[{"resourceType":"instance","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate"}]},{"resourceType":"volume","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate"}]}],"userData":{"Fn::Base64":{"Fn::Join":["",["Remove-Item -Recurse C:\\ProgramData\\Amazon\\ECS\\Cache\nImport-Module ECSTools\n[Environment]::SetEnvironmentVariable(\"ECS_CLUSTER\", \"",{"Ref":"ClusterEB0386A7"},"\", \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE\", \"true\", \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_AVAILABLE_LOGGING_DRIVERS\", '[\"json-file\",\"awslogs\"]', \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_ENABLE_TASK_IAM_ROLE\", \"true\", \"Machine\")\nInitialize-ECSAgent -Cluster '",{"Ref":"ClusterEB0386A7"},"' -EnableTaskIAMRole"]]}}},"tagSpecifications":[{"resourceType":"launch-template","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core/LaunchTemplate"}]}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"ASG":{"id":"ASG","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/ASG","attributes":{"aws:cdk:cloudformation:type":"AWS::AutoScaling::AutoScalingGroup","aws:cdk:cloudformation:props":{"launchTemplate":{"launchTemplateId":{"Ref":"ASGWin2022CoreLaunchTemplateEC9D9176"},"version":{"Fn::GetAtt":["ASGWin2022CoreLaunchTemplateEC9D9176","LatestVersionNumber"]}},"maxSize":"1","minSize":"0","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core","propagateAtLaunch":true}],"vpcZoneIdentifier":[{"Ref":"VpcPrivateSubnet1Subnet536B997A"},{"Ref":"VpcPrivateSubnet2Subnet3788AAA1"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DrainECSHook":{"id":"DrainECSHook","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook","children":{"Function":{"id":"Function","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function","children":{"ServiceRole":{"id":"ServiceRole","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole","children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}],"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/ServiceRole/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["ec2:DescribeHosts","ec2:DescribeInstanceAttribute","ec2:DescribeInstanceStatus","ec2:DescribeInstances"],"Effect":"Allow","Resource":"*"},{"Action":"autoscaling:CompleteLifecycleAction","Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":autoscaling:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":autoScalingGroup:*:autoScalingGroupName/",{"Ref":"ASGWin2022CoreASGBB924878"}]]}},{"Action":["ecs:DescribeContainerInstances","ecs:DescribeTasks","ecs:ListTasks","ecs:UpdateContainerInstancesState"],"Condition":{"ArnEquals":{"ecs:cluster":{"Fn::GetAtt":["ClusterEB0386A7","Arn"]}}},"Effect":"Allow","Resource":"*"},{"Action":["ecs:ListContainerInstances","ecs:SubmitContainerStateChange","ecs:SubmitTaskStateChange"],"Effect":"Allow","Resource":{"Fn::GetAtt":["ClusterEB0386A7","Arn"]}}],"Version":"2012-10-17"},"policyName":"ASGWin2022CoreDrainECSHookFunctionServiceRoleDefaultPolicy91DA5587","roles":[{"Ref":"ASGWin2022CoreDrainECSHookFunctionServiceRoleDEB0FB03"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*","*","*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(dict(event, ResponseURL='...')))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(dict(event, ResponseURL='...')))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n\n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n\n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n\n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n"},"environment":{"variables":{"CLUSTER":{"Ref":"ClusterEB0386A7"}}},"handler":"index.lambda_handler","role":{"Fn::GetAtt":["ASGWin2022CoreDrainECSHookFunctionServiceRoleDEB0FB03","Arn"]},"runtime":"python3.9","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core"}],"timeout":310}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"AllowInvoke:integecswindowscoreamiASGWin2022CoreLifecycleHookDrainHookTopicE3196F76":{"id":"AllowInvoke:integecswindowscoreamiASGWin2022CoreLifecycleHookDrainHookTopicE3196F76","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/AllowInvoke:integecswindowscoreamiASGWin2022CoreLifecycleHookDrainHookTopicE3196F76","attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["ASGWin2022CoreDrainECSHookFunction9D903E21","Arn"]},"principal":"sns.amazonaws.com","sourceArn":{"Ref":"ASGWin2022CoreLifecycleHookDrainHookTopicFA049579"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Topic":{"id":"Topic","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/Topic","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/DrainECSHook/Function/Topic/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::SNS::Subscription","aws:cdk:cloudformation:props":{"endpoint":{"Fn::GetAtt":["ASGWin2022CoreDrainECSHookFunction9D903E21","Arn"]},"protocol":"lambda","topicArn":{"Ref":"ASGWin2022CoreLifecycleHookDrainHookTopicFA049579"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"LifecycleHookDrainHook":{"id":"LifecycleHookDrainHook","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook","children":{"Topic":{"id":"Topic","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Topic","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Topic/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::SNS::Topic","aws:cdk:cloudformation:props":{"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Role":{"id":"Role","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role","children":{"ImportRole":{"id":"ImportRole","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role/ImportRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"autoscaling.amazonaws.com"}}],"Version":"2012-10-17"},"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2022Core"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Role/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"sns:Publish","Effect":"Allow","Resource":{"Ref":"ASGWin2022CoreLifecycleHookDrainHookTopicFA049579"}}],"Version":"2012-10-17"},"policyName":"ASGWin2022CoreLifecycleHookDrainHookRoleDefaultPolicyEC5E58D9","roles":[{"Ref":"ASGWin2022CoreLifecycleHookDrainHookRole067A0289"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2022Core/LifecycleHookDrainHook/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::AutoScaling::LifecycleHook","aws:cdk:cloudformation:props":{"autoScalingGroupName":{"Ref":"ASGWin2022CoreASGBB924878"},"defaultResult":"CONTINUE","heartbeatTimeout":300,"lifecycleTransition":"autoscaling:EC2_INSTANCE_TERMINATING","notificationTargetArn":{"Ref":"ASGWin2022CoreLifecycleHookDrainHookTopicFA049579"},"roleArn":{"Fn::GetAtt":["ASGWin2022CoreLifecycleHookDrainHookRole067A0289","Arn"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*","*","*","*","*","*"]}},"SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2022-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter":{"id":"SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2022-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter","path":"integ-ecs-windows-core-ami/SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2022-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2022-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118":{"id":"SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2022-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118","path":"integ-ecs-windows-core-ami/SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2022-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"EC2CapacityProvider2022Core":{"id":"EC2CapacityProvider2022Core","path":"integ-ecs-windows-core-ami/EC2CapacityProvider2022Core","children":{"EC2CapacityProvider2022Core":{"id":"EC2CapacityProvider2022Core","path":"integ-ecs-windows-core-ami/EC2CapacityProvider2022Core/EC2CapacityProvider2022Core","attributes":{"aws:cdk:cloudformation:type":"AWS::ECS::CapacityProvider","aws:cdk:cloudformation:props":{"autoScalingGroupProvider":{"autoScalingGroupArn":{"Ref":"ASGWin2022CoreASGBB924878"},"managedScaling":{"status":"ENABLED","targetCapacity":100},"managedTerminationProtection":"DISABLED"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"ASG-Win2019Core":{"id":"ASG-Win2019Core","path":"integ-ecs-windows-core-ami/ASG-Win2019Core","children":{"InstanceSecurityGroup":{"id":"InstanceSecurityGroup","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceSecurityGroup","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceSecurityGroup/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::SecurityGroup","aws:cdk:cloudformation:props":{"groupDescription":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceSecurityGroup","securityGroupEgress":[{"cidrIp":"0.0.0.0/0","description":"Allow all outbound traffic by default","ipProtocol":"-1"}],"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core"}],"vpcId":{"Ref":"Vpc8378EB38"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"InstanceRole":{"id":"InstanceRole","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole","children":{"ImportInstanceRole":{"id":"ImportInstanceRole","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole/ImportInstanceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"}}],"Version":"2012-10-17"},"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceRole/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["ecs:DeregisterContainerInstance","ecs:RegisterContainerInstance","ecs:Submit*"],"Effect":"Allow","Resource":{"Fn::GetAtt":["ClusterEB0386A7","Arn"]}},{"Action":["ecs:Poll","ecs:StartTelemetrySession"],"Condition":{"ArnEquals":{"ecs:cluster":{"Fn::GetAtt":["ClusterEB0386A7","Arn"]}}},"Effect":"Allow","Resource":"*"},{"Action":["ecr:GetAuthorizationToken","ecs:DiscoverPollEndpoint","logs:CreateLogStream","logs:PutLogEvents"],"Effect":"Allow","Resource":"*"}],"Version":"2012-10-17"},"policyName":"ASGWin2019CoreInstanceRoleDefaultPolicy93C292B8","roles":[{"Ref":"ASGWin2019CoreInstanceRole789AFEC5"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*"]}},"InstanceProfile":{"id":"InstanceProfile","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/InstanceProfile","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::InstanceProfile","aws:cdk:cloudformation:props":{"roles":[{"Ref":"ASGWin2019CoreInstanceRole789AFEC5"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"ImportedInstanceProfile":{"id":"ImportedInstanceProfile","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/ImportedInstanceProfile","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"LaunchTemplate":{"id":"LaunchTemplate","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::EC2::LaunchTemplate","aws:cdk:cloudformation:props":{"launchTemplateData":{"iamInstanceProfile":{"arn":{"Fn::GetAtt":["ASGWin2019CoreInstanceProfileBF14CDCB","Arn"]}},"imageId":{"Ref":"SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishCoreECSOptimizedimageidC96584B6F00A464EAD1953AFF4B05118Parameter"},"instanceType":"t2.micro","monitoring":{"enabled":false},"securityGroupIds":[{"Fn::GetAtt":["ASGWin2019CoreInstanceSecurityGroup98D7D0D0","GroupId"]}],"tagSpecifications":[{"resourceType":"instance","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate"}]},{"resourceType":"volume","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate"}]}],"userData":{"Fn::Base64":{"Fn::Join":["",["Remove-Item -Recurse C:\\ProgramData\\Amazon\\ECS\\Cache\nImport-Module ECSTools\n[Environment]::SetEnvironmentVariable(\"ECS_CLUSTER\", \"",{"Ref":"ClusterEB0386A7"},"\", \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE\", \"true\", \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_AVAILABLE_LOGGING_DRIVERS\", '[\"json-file\",\"awslogs\"]', \"Machine\")\n[Environment]::SetEnvironmentVariable(\"ECS_ENABLE_TASK_IAM_ROLE\", \"true\", \"Machine\")\nInitialize-ECSAgent -Cluster '",{"Ref":"ClusterEB0386A7"},"' -EnableTaskIAMRole"]]}}},"tagSpecifications":[{"resourceType":"launch-template","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core/LaunchTemplate"}]}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"ASG":{"id":"ASG","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/ASG","attributes":{"aws:cdk:cloudformation:type":"AWS::AutoScaling::AutoScalingGroup","aws:cdk:cloudformation:props":{"launchTemplate":{"launchTemplateId":{"Ref":"ASGWin2019CoreLaunchTemplate9CDB8014"},"version":{"Fn::GetAtt":["ASGWin2019CoreLaunchTemplate9CDB8014","LatestVersionNumber"]}},"maxSize":"1","minSize":"0","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core","propagateAtLaunch":true}],"vpcZoneIdentifier":[{"Ref":"VpcPrivateSubnet1Subnet536B997A"},{"Ref":"VpcPrivateSubnet2Subnet3788AAA1"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DrainECSHook":{"id":"DrainECSHook","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook","children":{"Function":{"id":"Function","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function","children":{"ServiceRole":{"id":"ServiceRole","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole","children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}],"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/ServiceRole/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["ec2:DescribeHosts","ec2:DescribeInstanceAttribute","ec2:DescribeInstanceStatus","ec2:DescribeInstances"],"Effect":"Allow","Resource":"*"},{"Action":"autoscaling:CompleteLifecycleAction","Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":autoscaling:",{"Ref":"AWS::Region"},":",{"Ref":"AWS::AccountId"},":autoScalingGroup:*:autoScalingGroupName/",{"Ref":"ASGWin2019CoreASG09FBC80E"}]]}},{"Action":["ecs:DescribeContainerInstances","ecs:DescribeTasks","ecs:ListTasks","ecs:UpdateContainerInstancesState"],"Condition":{"ArnEquals":{"ecs:cluster":{"Fn::GetAtt":["ClusterEB0386A7","Arn"]}}},"Effect":"Allow","Resource":"*"},{"Action":["ecs:ListContainerInstances","ecs:SubmitContainerStateChange","ecs:SubmitTaskStateChange"],"Effect":"Allow","Resource":{"Fn::GetAtt":["ClusterEB0386A7","Arn"]}}],"Version":"2012-10-17"},"policyName":"ASGWin2019CoreDrainECSHookFunctionServiceRoleDefaultPolicy852E2B97","roles":[{"Ref":"ASGWin2019CoreDrainECSHookFunctionServiceRole74692A98"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*","*","*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"import boto3, json, os, time\n\necs = boto3.client('ecs')\nautoscaling = boto3.client('autoscaling')\n\n\ndef lambda_handler(event, context):\n print(json.dumps(dict(event, ResponseURL='...')))\n cluster = os.environ['CLUSTER']\n snsTopicArn = event['Records'][0]['Sns']['TopicArn']\n lifecycle_event = json.loads(event['Records'][0]['Sns']['Message'])\n instance_id = lifecycle_event.get('EC2InstanceId')\n if not instance_id:\n print('Got event without EC2InstanceId: %s', json.dumps(dict(event, ResponseURL='...')))\n return\n\n instance_arn = container_instance_arn(cluster, instance_id)\n print('Instance %s has container instance ARN %s' % (lifecycle_event['EC2InstanceId'], instance_arn))\n\n if not instance_arn:\n return\n\n task_arns = container_instance_task_arns(cluster, instance_arn)\n\n if task_arns:\n print('Instance ARN %s has task ARNs %s' % (instance_arn, ', '.join(task_arns)))\n\n while has_tasks(cluster, instance_arn, task_arns):\n time.sleep(10)\n\n try:\n print('Terminating instance %s' % instance_id)\n autoscaling.complete_lifecycle_action(\n LifecycleActionResult='CONTINUE',\n **pick(lifecycle_event, 'LifecycleHookName', 'LifecycleActionToken', 'AutoScalingGroupName'))\n except Exception as e:\n # Lifecycle action may have already completed.\n print(str(e))\n\n\ndef container_instance_arn(cluster, instance_id):\n \"\"\"Turn an instance ID into a container instance ARN.\"\"\"\n arns = ecs.list_container_instances(cluster=cluster, filter='ec2InstanceId==' + instance_id)['containerInstanceArns']\n if not arns:\n return None\n return arns[0]\n\ndef container_instance_task_arns(cluster, instance_arn):\n \"\"\"Fetch tasks for a container instance ARN.\"\"\"\n arns = ecs.list_tasks(cluster=cluster, containerInstance=instance_arn)['taskArns']\n return arns\n\ndef has_tasks(cluster, instance_arn, task_arns):\n \"\"\"Return True if the instance is running tasks for the given cluster.\"\"\"\n instances = ecs.describe_container_instances(cluster=cluster, containerInstances=[instance_arn])['containerInstances']\n if not instances:\n return False\n instance = instances[0]\n\n if instance['status'] == 'ACTIVE':\n # Start draining, then try again later\n set_container_instance_to_draining(cluster, instance_arn)\n return True\n\n task_count = None\n\n if task_arns:\n # Fetch details for tasks running on the container instance\n tasks = ecs.describe_tasks(cluster=cluster, tasks=task_arns)['tasks']\n if tasks:\n # Consider any non-stopped tasks as running\n task_count = sum(task['lastStatus'] != 'STOPPED' for task in tasks) + instance['pendingTasksCount']\n\n if not task_count:\n # Fallback to instance task counts if detailed task information is unavailable\n task_count = instance['runningTasksCount'] + instance['pendingTasksCount']\n\n print('Instance %s has %s tasks' % (instance_arn, task_count))\n\n return task_count > 0\n\ndef set_container_instance_to_draining(cluster, instance_arn):\n ecs.update_container_instances_state(\n cluster=cluster,\n containerInstances=[instance_arn], status='DRAINING')\n\n\ndef pick(dct, *keys):\n \"\"\"Pick a subset of a dict.\"\"\"\n return {k: v for k, v in dct.items() if k in keys}\n"},"environment":{"variables":{"CLUSTER":{"Ref":"ClusterEB0386A7"}}},"handler":"index.lambda_handler","role":{"Fn::GetAtt":["ASGWin2019CoreDrainECSHookFunctionServiceRole74692A98","Arn"]},"runtime":"python3.9","tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core"}],"timeout":310}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"AllowInvoke:integecswindowscoreamiASGWin2019CoreLifecycleHookDrainHookTopic3026395C":{"id":"AllowInvoke:integecswindowscoreamiASGWin2019CoreLifecycleHookDrainHookTopic3026395C","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/AllowInvoke:integecswindowscoreamiASGWin2019CoreLifecycleHookDrainHookTopic3026395C","attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunction","functionName":{"Fn::GetAtt":["ASGWin2019CoreDrainECSHookFunction17A7DCA1","Arn"]},"principal":"sns.amazonaws.com","sourceArn":{"Ref":"ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Topic":{"id":"Topic","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/Topic","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/DrainECSHook/Function/Topic/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::SNS::Subscription","aws:cdk:cloudformation:props":{"endpoint":{"Fn::GetAtt":["ASGWin2019CoreDrainECSHookFunction17A7DCA1","Arn"]},"protocol":"lambda","topicArn":{"Ref":"ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"LifecycleHookDrainHook":{"id":"LifecycleHookDrainHook","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook","children":{"Topic":{"id":"Topic","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Topic","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Topic/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::SNS::Topic","aws:cdk:cloudformation:props":{"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Role":{"id":"Role","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role","children":{"ImportRole":{"id":"ImportRole","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role/ImportRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"autoscaling.amazonaws.com"}}],"Version":"2012-10-17"},"tags":[{"key":"Name","value":"integ-ecs-windows-core-ami/ASG-Win2019Core"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Role/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":"sns:Publish","Effect":"Allow","Resource":{"Ref":"ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1"}}],"Version":"2012-10-17"},"policyName":"ASGWin2019CoreLifecycleHookDrainHookRoleDefaultPolicy2CBAED41","roles":[{"Ref":"ASGWin2019CoreLifecycleHookDrainHookRole0BD06247"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}},"Resource":{"id":"Resource","path":"integ-ecs-windows-core-ami/ASG-Win2019Core/LifecycleHookDrainHook/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::AutoScaling::LifecycleHook","aws:cdk:cloudformation:props":{"autoScalingGroupName":{"Ref":"ASGWin2019CoreASG09FBC80E"},"defaultResult":"CONTINUE","heartbeatTimeout":300,"lifecycleTransition":"autoscaling:EC2_INSTANCE_TERMINATING","notificationTargetArn":{"Ref":"ASGWin2019CoreLifecycleHookDrainHookTopicBBBEFED1"},"roleArn":{"Fn::GetAtt":["ASGWin2019CoreLifecycleHookDrainHookRole0BD06247","Arn"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*","*","*","*","*","*","*","*"]}},"SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2019-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter":{"id":"SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2019-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter","path":"integ-ecs-windows-core-ami/SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2019-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2019-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118":{"id":"SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2019-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118","path":"integ-ecs-windows-core-ami/SsmParameterValue:--aws--service--ami-windows-latest--Windows_Server-2019-English-Core-ECS_Optimized--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"EC2CapacityProvider2019Core":{"id":"EC2CapacityProvider2019Core","path":"integ-ecs-windows-core-ami/EC2CapacityProvider2019Core","children":{"EC2CapacityProvider2019Core":{"id":"EC2CapacityProvider2019Core","path":"integ-ecs-windows-core-ami/EC2CapacityProvider2019Core/EC2CapacityProvider2019Core","attributes":{"aws:cdk:cloudformation:type":"AWS::ECS::CapacityProvider","aws:cdk:cloudformation:props":{"autoScalingGroupProvider":{"autoScalingGroupArn":{"Ref":"ASGWin2019CoreASG09FBC80E"},"managedScaling":{"status":"ENABLED","targetCapacity":100},"managedTerminationProtection":"DISABLED"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"BootstrapVersion":{"id":"BootstrapVersion","path":"integ-ecs-windows-core-ami/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"integ-ecs-windows-core-ami/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"ClusterWindowsCoreAmi":{"id":"ClusterWindowsCoreAmi","path":"ClusterWindowsCoreAmi","children":{"DefaultTest":{"id":"DefaultTest","path":"ClusterWindowsCoreAmi/DefaultTest","children":{"Default":{"id":"Default","path":"ClusterWindowsCoreAmi/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"ClusterWindowsCoreAmi/DefaultTest/DeployAssert","children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"ClusterWindowsCoreAmi/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"ClusterWindowsCoreAmi/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"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":"constructs.Construct","version":"10.4.2"}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.ts new file mode 100644 index 0000000000000..337018370cb96 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-windows-core-ami.ts @@ -0,0 +1,89 @@ +import * as autoscaling from 'aws-cdk-lib/aws-autoscaling'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as cdk from 'aws-cdk-lib'; +import * as ecs from 'aws-cdk-lib/aws-ecs'; +import * as integ from '@aws-cdk/integ-tests-alpha'; + +/** + * Integration test for Windows Server Core AMI support + * + * This test uses the WindowsOptimizedCoreVersion enum and windowsCore() method + * to create ECS capacity providers with Windows Core AMIs. + */ + +const app = new cdk.App({ + postCliContext: { + '@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature': false, + '@aws-cdk/aws-ecs:disableEcsImdsBlocking': false, + '@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy': false, + }, +}); + +const stack = new cdk.Stack(app, 'integ-ecs-windows-core-ami'); + +const vpc = new ec2.Vpc(stack, 'Vpc', { + maxAzs: 2, + restrictDefaultSecurityGroup: false, +}); + +const cluster = new ecs.Cluster(stack, 'Cluster', { + vpc, +}); + +// Create an ASG using Windows Server 2022 Core +const autoScalingGroup2022Core = new autoscaling.AutoScalingGroup( + stack, + 'ASG-Win2022Core', + { + vpc, + instanceType: new ec2.InstanceType('t2.micro'), + machineImage: ecs.EcsOptimizedImage.windowsCore( + ecs.WindowsOptimizedCoreVersion.SERVER_2022_CORE, + ), + minCapacity: 0, + }, +); + +const cp2022 = new ecs.AsgCapacityProvider( + stack, + 'EC2CapacityProvider2022Core', + { + autoScalingGroup: autoScalingGroup2022Core, + enableManagedTerminationProtection: false, + }, +); + +// Create an ASG using Windows Server 2019 Core +const autoScalingGroup2019Core = new autoscaling.AutoScalingGroup( + stack, + 'ASG-Win2019Core', + { + vpc, + instanceType: new ec2.InstanceType('t2.micro'), + // Use the regular windows method for now + // We'll change this to windowsCore() after PR is merged + machineImage: ecs.EcsOptimizedImage.windowsCore( + ecs.WindowsOptimizedCoreVersion.SERVER_2019_CORE, + ), + minCapacity: 0, + }, +); + +const cp2019 = new ecs.AsgCapacityProvider( + stack, + 'EC2CapacityProvider2019Core', + { + autoScalingGroup: autoScalingGroup2019Core, + enableManagedTerminationProtection: false, + }, +); + +// Add both capacity providers to the cluster +cluster.addAsgCapacityProvider(cp2022); +cluster.addAsgCapacityProvider(cp2019); + +new integ.IntegTest(app, 'ClusterWindowsCoreAmi', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/aws-cdk-lib/aws-ecs/README.md b/packages/aws-cdk-lib/aws-ecs/README.md index 6c2e012066316..009bc1b139f9e 100644 --- a/packages/aws-cdk-lib/aws-ecs/README.md +++ b/packages/aws-cdk-lib/aws-ecs/README.md @@ -306,6 +306,25 @@ cluster.addCapacity('graviton-cluster', { }); ``` +### Amazon Linux 2 Kernel Versions + +You can specify a specific kernel version for your Amazon Linux 2 ECS-optimized AMI using the `AmiLinuxKernelVersion` enum. + +```ts +declare const cluster: ecs.Cluster; + +cluster.addCapacity('al2-kernel-5.10-cluster', { + minCapacity: 2, + instanceType: new ec2.InstanceType('c5.large'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2( + ecs.AmiHardwareType.STANDARD, + { kernel: ecs.AmiLinuxKernelVersion.KERNEL_5_10 }, + ), +}); +``` + +This is particularly useful when you need to ensure your ECS tasks run on instances with a specific kernel version for compatibility or feature requirements. + ### Amazon Linux 2 (Neuron) Instances To launch Amazon EC2 Inf1, Trn1 or Inf2 instances, you can use the Amazon ECS optimized Amazon Linux 2 (Neuron) AMI. It comes pre-configured with AWS Inferentia and AWS Trainium drivers and the AWS Neuron runtime for Docker which makes running machine learning inference workloads easier on Amazon ECS. diff --git a/packages/aws-cdk-lib/aws-ecs/lib/amis.ts b/packages/aws-cdk-lib/aws-ecs/lib/amis.ts index 7b82d7dcb5017..50b6803a46e8e 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/amis.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/amis.ts @@ -42,6 +42,31 @@ export enum WindowsOptimizedVersion { SERVER_2016 = '2016', } +/** + * Windows Server Core variants for ECS-optimized AMIs. + */ +export enum WindowsOptimizedCoreVersion { + /** + * Windows Server 2022 Core + */ + SERVER_2022_CORE = '2022', + + /** + * Windows Server 2019 Core + */ + SERVER_2019_CORE = '2019', +} + +/** + * The kernel version for Amazon Linux 2 ECS-optimized AMI. + */ +export enum AmiLinuxKernelVersion { + /** + * Kernel version 5.10 + */ + KERNEL_5_10 = '5.10', +} + const BR_IMAGE_SYMBOL = Symbol.for( '@aws-cdk/aws-ecs/lib/amis.BottleRocketImage', ); @@ -71,6 +96,13 @@ export interface EcsOptimizedAmiProps { */ readonly windowsVersion?: WindowsOptimizedVersion; + /** + * The Windows Server Core version to use. + * + * @default none, uses Linux generation + */ + readonly windowsCoreVersion?: WindowsOptimizedCoreVersion; + /** * The ECS-optimized AMI variant to use. * @@ -99,6 +131,13 @@ export interface EcsOptimizedAmiProps { */ readonly cachedInContext?: boolean; + /** + * The kernel version to use for Amazon Linux 2. + * + * @default - kernel value will be undefined + */ + readonly kernel?: AmiLinuxKernelVersion; + /** * Adds an additional discriminator to the `cdk.context.json` cache key. * @@ -107,6 +146,68 @@ export interface EcsOptimizedAmiProps { readonly additionalCacheKey?: string; } +/** + * Internal utility for constructing the SSM parameter path for ECS AMIs. + * Used by both EcsOptimizedAmi and EcsOptimizedImage classes. + */ +function constructSsmParameterPath(params: { + windowsVersion?: WindowsOptimizedVersion; + windowsCoreVersion?: WindowsOptimizedCoreVersion; + generation?: ec2.AmazonLinuxGeneration; + hwType: AmiHardwareType; + kernel?: AmiLinuxKernelVersion; +}): string { + let path = '/aws/service/'; + + if (params.windowsVersion || params.windowsCoreVersion) { + path += 'ami-windows-latest/'; + + let windowsVersion: string; + let editionType: string; + + if (params.windowsCoreVersion) { + // For Core variants + windowsVersion = params.windowsCoreVersion; + editionType = 'English-Core'; + } else { + // For Full editions + windowsVersion = params.windowsVersion!; + editionType = 'English-Full'; + } + + path += `Windows_Server-${windowsVersion}-${editionType}-ECS_Optimized/`; + path += 'image_id'; + } else { + path += 'ecs/optimized-ami/'; + + if (params.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX) { + path += 'amazon-linux/'; + } else if (params.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2) { + path += 'amazon-linux-2/'; + + // Add kernel version for Amazon Linux 2 if specified + if (params.kernel) { + path += `kernel-${params.kernel}/`; + } + } else if (params.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2023) { + path += 'amazon-linux-2023/'; + } + + // Add hardware type + if (params.hwType === AmiHardwareType.GPU) { + path += 'gpu/'; + } else if (params.hwType === AmiHardwareType.ARM) { + path += 'arm64/'; + } else if (params.hwType === AmiHardwareType.NEURON) { + path += 'inf/'; + } + + path += 'recommended/image_id'; + } + + return path; +} + /* * TODO:v2.0.0 remove EcsOptimizedAmi */ @@ -118,6 +219,7 @@ export interface EcsOptimizedAmiProps { export class EcsOptimizedAmi implements ec2.IMachineImage { private readonly generation?: ec2.AmazonLinuxGeneration; private readonly windowsVersion?: WindowsOptimizedVersion; + private readonly windowsCoreVersion?: WindowsOptimizedCoreVersion; private readonly hwType: AmiHardwareType; private readonly amiParameterName: string; @@ -129,10 +231,17 @@ export class EcsOptimizedAmi implements ec2.IMachineImage { */ constructor(props?: EcsOptimizedAmiProps) { this.hwType = (props && props.hardwareType) || AmiHardwareType.STANDARD; - if (props && props.generation) { // generation defined in the props object + + // Multiple OS/version validation + if (props?.windowsVersion && props?.windowsCoreVersion) { + throw new UnscopedValidationError('Cannot specify both windowsVersion and windowsCoreVersion'); + } + + if (props && props.generation) { + // generation defined in the props object if (props.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX && this.hwType !== AmiHardwareType.STANDARD) { throw new UnscopedValidationError('Amazon Linux does not support special hardware type. Use Amazon Linux 2 instead'); - } else if (props.windowsVersion) { + } else if (props.windowsVersion || props.windowsCoreVersion) { throw new UnscopedValidationError('"windowsVersion" and Linux image "generation" cannot be both set'); } else { this.generation = props.generation; @@ -143,22 +252,26 @@ export class EcsOptimizedAmi implements ec2.IMachineImage { } else { this.windowsVersion = props.windowsVersion; } - } else { // generation not defined in props object + } else if (props && props.windowsCoreVersion) { + if (this.hwType !== AmiHardwareType.STANDARD) { + throw new UnscopedValidationError('Windows Server Core does not support special hardware type'); + } else { + this.windowsCoreVersion = props.windowsCoreVersion; + } + } else { + // no OS/version specified // always default to Amazon Linux v2 regardless of HW this.generation = ec2.AmazonLinuxGeneration.AMAZON_LINUX_2; } - // set the SSM parameter name - this.amiParameterName = '/aws/service/' - + (this.windowsVersion ? 'ami-windows-latest/' : 'ecs/optimized-ami/') - + (this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX ? 'amazon-linux/' : '') - + (this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 ? 'amazon-linux-2/' : '') - + (this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2023 ? 'amazon-linux-2023/' : '') - + (this.windowsVersion ? `Windows_Server-${this.windowsVersion}-English-Full-ECS_Optimized/` : '') - + (this.hwType === AmiHardwareType.GPU ? 'gpu/' : '') - + (this.hwType === AmiHardwareType.ARM ? 'arm64/' : '') - + (this.hwType === AmiHardwareType.NEURON ? 'inf/' : '') - + (this.windowsVersion ? 'image_id' : 'recommended/image_id'); + // Use the shared utility function to construct the SSM parameter path + this.amiParameterName = constructSsmParameterPath({ + windowsVersion: this.windowsVersion, + windowsCoreVersion: this.windowsCoreVersion, + generation: this.generation, + hwType: this.hwType, + kernel: props?.kernel, + }); this.cachedInContext = props?.cachedInContext ?? false; this.additionalCacheKey = props?.additionalCacheKey; @@ -174,7 +287,12 @@ export class EcsOptimizedAmi implements ec2.IMachineImage { public getImage(scope: Construct): ec2.MachineImageConfig { const ami = lookupImage(scope, this.cachedInContext, this.amiParameterName, this.additionalCacheKey); - const osType = this.windowsVersion ? ec2.OperatingSystemType.WINDOWS : ec2.OperatingSystemType.LINUX; + // Windows OS type for both regular Windows and Windows Core variants + const osType = + this.windowsVersion || this.windowsCoreVersion + ? ec2.OperatingSystemType.WINDOWS + : ec2.OperatingSystemType.LINUX; + return { imageId: ami, osType, @@ -208,6 +326,13 @@ export interface EcsOptimizedImageOptions { */ readonly cachedInContext?: boolean; + /** + * The kernel version to use for Amazon Linux 2. + * + * @default - kernel value will be undefined + */ + readonly kernel?: AmiLinuxKernelVersion; + /** * Adds an additional discriminator to the `cdk.context.json` cache key. * @@ -230,6 +355,7 @@ export class EcsOptimizedImage implements ec2.IMachineImage { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2023, hardwareType, cachedInContext: options.cachedInContext, + additionalCacheKey: options.additionalCacheKey, }); } @@ -237,12 +363,18 @@ export class EcsOptimizedImage implements ec2.IMachineImage { * Construct an Amazon Linux 2 image from the latest ECS Optimized AMI published in SSM * * @param hardwareType ECS-optimized AMI variant to use + * @param Additional options to configure `EcsOptimizedImage` */ - public static amazonLinux2(hardwareType = AmiHardwareType.STANDARD, options: EcsOptimizedImageOptions = {}): EcsOptimizedImage { + public static amazonLinux2( + hardwareType = AmiHardwareType.STANDARD, + options: EcsOptimizedImageOptions = {}, + ): EcsOptimizedImage { return new EcsOptimizedImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, hardwareType, cachedInContext: options.cachedInContext, + kernel: options.kernel, + additionalCacheKey: options.additionalCacheKey, }); } @@ -253,6 +385,7 @@ export class EcsOptimizedImage implements ec2.IMachineImage { return new EcsOptimizedImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX, cachedInContext: options.cachedInContext, + additionalCacheKey: options.additionalCacheKey, }); } @@ -265,11 +398,29 @@ export class EcsOptimizedImage implements ec2.IMachineImage { return new EcsOptimizedImage({ windowsVersion, cachedInContext: options.cachedInContext, + additionalCacheKey: options.additionalCacheKey, + }); + } + + /** + * Construct a Windows Server Core image from the latest ECS Optimized AMI published in SSM + * + * @param coreVersion Windows Server Core version to use + */ + public static windowsCore( + coreVersion: WindowsOptimizedCoreVersion, + options: EcsOptimizedImageOptions = {}, + ): EcsOptimizedImage { + return new EcsOptimizedImage({ + windowsCoreVersion: coreVersion, + cachedInContext: options.cachedInContext, + additionalCacheKey: options.additionalCacheKey, }); } private readonly generation?: ec2.AmazonLinuxGeneration; private readonly windowsVersion?: WindowsOptimizedVersion; + private readonly windowsCoreVersion?: WindowsOptimizedCoreVersion; private readonly hwType?: AmiHardwareType; private readonly amiParameterName: string; @@ -280,27 +431,48 @@ export class EcsOptimizedImage implements ec2.IMachineImage { * Constructs a new instance of the EcsOptimizedAmi class. */ private constructor(props: EcsOptimizedAmiProps) { - this.hwType = props && props.hardwareType; + this.hwType = props?.hardwareType; + this.windowsCoreVersion = props?.windowsCoreVersion; + + // Check for conflicting OS/version specifications + if ((props?.windowsVersion && props?.windowsCoreVersion) || + (props?.windowsVersion && props?.generation) || + (props?.windowsCoreVersion && props?.generation)) { + throw new UnscopedValidationError('Cannot specify more than one of: windowsVersion, windowsCoreVersion, or generation'); + } - if (props.windowsVersion) { + if (props?.windowsVersion) { + // Validate hardware type compatibility with Windows + if (props.hardwareType && props.hardwareType !== AmiHardwareType.STANDARD) { + throw new UnscopedValidationError('Windows Server does not support special hardware types'); + } this.windowsVersion = props.windowsVersion; - } else if (props.generation) { + } else if (props?.windowsCoreVersion) { + // Validate hardware type compatibility with Windows Core + if (props.hardwareType && props.hardwareType !== AmiHardwareType.STANDARD) { + throw new UnscopedValidationError('Windows Server Core does not support special hardware types'); + } + this.windowsCoreVersion = props.windowsCoreVersion; + } else if (props?.generation) { + // Validate hardware type compatibility with Amazon Linux + if (props.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX && + props.hardwareType && props.hardwareType !== AmiHardwareType.STANDARD) { + throw new UnscopedValidationError('Amazon Linux does not support special hardware types. Use Amazon Linux 2 instead'); + } this.generation = props.generation; } else { - throw new UnscopedValidationError('This error should never be thrown'); + // Default to Amazon Linux 2 if no OS/version is specified + this.generation = ec2.AmazonLinuxGeneration.AMAZON_LINUX_2; } - // set the SSM parameter name - this.amiParameterName = '/aws/service/' - + (this.windowsVersion ? 'ami-windows-latest/' : 'ecs/optimized-ami/') - + (this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX ? 'amazon-linux/' : '') - + (this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 ? 'amazon-linux-2/' : '') - + (this.generation === ec2.AmazonLinuxGeneration.AMAZON_LINUX_2023 ? 'amazon-linux-2023/' : '') - + (this.windowsVersion ? `Windows_Server-${this.windowsVersion}-English-Full-ECS_Optimized/` : '') - + (this.hwType === AmiHardwareType.GPU ? 'gpu/' : '') - + (this.hwType === AmiHardwareType.ARM ? 'arm64/' : '') - + (this.hwType === AmiHardwareType.NEURON ? 'inf/' : '') - + (this.windowsVersion ? 'image_id' : 'recommended/image_id'); + // Use the shared utility function to construct the SSM parameter path + this.amiParameterName = constructSsmParameterPath({ + windowsVersion: this.windowsVersion, + windowsCoreVersion: this.windowsCoreVersion, + generation: this.generation, + hwType: this.hwType ?? AmiHardwareType.STANDARD, + kernel: props.kernel, + }); this.cachedInContext = props.cachedInContext ?? false; this.additionalCacheKey = props.additionalCacheKey; @@ -316,7 +488,12 @@ export class EcsOptimizedImage implements ec2.IMachineImage { public getImage(scope: Construct): ec2.MachineImageConfig { const ami = lookupImage(scope, this.cachedInContext, this.amiParameterName, this.additionalCacheKey); - const osType = this.windowsVersion ? ec2.OperatingSystemType.WINDOWS : ec2.OperatingSystemType.LINUX; + // Windows OS type for both regular Windows and Windows Core variants + const osType = + this.windowsVersion || this.windowsCoreVersion + ? ec2.OperatingSystemType.WINDOWS + : ec2.OperatingSystemType.LINUX; + return { imageId: ami, osType, diff --git a/packages/aws-cdk-lib/aws-ecs/test/amis.test.ts b/packages/aws-cdk-lib/aws-ecs/test/amis.test.ts index f5bf64f419325..7cdf004b30582 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/amis.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/amis.test.ts @@ -1,12 +1,25 @@ +import * as ec2 from '../../aws-ec2'; import * as cdk from '../../core'; import * as ecs from '../lib'; describe('amis', () => { test.each([ - [ecs.BottlerocketEcsVariant.AWS_ECS_1, 'SsmParameterValueawsservicebottlerocketawsecs1x8664'], - [ecs.BottlerocketEcsVariant.AWS_ECS_1_NVIDIA, 'SsmParameterValueawsservicebottlerocketawsecs1nvidiax8664'], - [ecs.BottlerocketEcsVariant.AWS_ECS_2, 'SsmParameterValueawsservicebottlerocketawsecs2x8664'], - [ecs.BottlerocketEcsVariant.AWS_ECS_2_NVIDIA, 'SsmParameterValueawsservicebottlerocketawsecs2nvidiax8664'], + [ + ecs.BottlerocketEcsVariant.AWS_ECS_1, + 'SsmParameterValueawsservicebottlerocketawsecs1x8664', + ], + [ + ecs.BottlerocketEcsVariant.AWS_ECS_1_NVIDIA, + 'SsmParameterValueawsservicebottlerocketawsecs1nvidiax8664', + ], + [ + ecs.BottlerocketEcsVariant.AWS_ECS_2, + 'SsmParameterValueawsservicebottlerocketawsecs2x8664', + ], + [ + ecs.BottlerocketEcsVariant.AWS_ECS_2_NVIDIA, + 'SsmParameterValueawsservicebottlerocketawsecs2nvidiax8664', + ], ])('BottleRocketImage with %s variant', (variant, ssmKey) => { // GIVEN const app = new cdk.App(); @@ -19,9 +32,205 @@ describe('amis', () => { // THEN const assembly = app.synth(); - const parameters = assembly.getStackByName(stack.stackName).template.Parameters; - expect(Object.entries(parameters).some( - ([k, v]) => k.startsWith(ssmKey) && (v as any).Default.includes(`/bottlerocket/${variant}/x86_64/`), - )).toEqual(true); + const parameters = assembly.getStackByName(stack.stackName).template + .Parameters; + expect( + Object.entries(parameters).some( + ([k, v]) => + k.startsWith(ssmKey) && + (v as any).Default.includes(`/bottlerocket/${variant}/x86_64/`), + ), + ).toEqual(true); + }); + + test.each([ + [ecs.WindowsOptimizedVersion.SERVER_2022, '2022', 'Full'], + [ecs.WindowsOptimizedVersion.SERVER_2019, '2019', 'Full'], + [ecs.WindowsOptimizedVersion.SERVER_2016, '2016', 'Full'], + ])( + 'Windows Server variants with %s', + (windowsVersion, baseVersion, editionType) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + + // WHEN + ecs.EcsOptimizedImage.windows(windowsVersion).getImage(stack); + + // THEN + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template + .Parameters; + expect( + Object.entries(parameters).some( + ([k, v]) => + k.startsWith('SsmParameterValue') && + (v as any).Default.includes( + `/ami-windows-latest/Windows_Server-${baseVersion}-English-${editionType}-ECS_Optimized/`, + ), + ), + ).toEqual(true); + }, + ); + + test.each([ + [ecs.WindowsOptimizedCoreVersion.SERVER_2022_CORE, '2022', 'Core'], + [ecs.WindowsOptimizedCoreVersion.SERVER_2019_CORE, '2019', 'Core'], + ])( + 'Windows Server Core variants with %s', + (coreVersion, baseVersion, editionType) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + + // WHEN + ecs.EcsOptimizedImage.windowsCore(coreVersion).getImage(stack); + + // THEN + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template + .Parameters; + expect( + Object.entries(parameters).some( + ([k, v]) => + k.startsWith('SsmParameterValue') && + (v as any).Default.includes( + `/ami-windows-latest/Windows_Server-${baseVersion}-English-${editionType}-ECS_Optimized/`, + ), + ), + ).toEqual(true); + }, + ); + + test('Amazon Linux 2 with kernel 5.10', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + + // WHEN + ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.STANDARD, { + kernel: ecs.AmiLinuxKernelVersion.KERNEL_5_10, + }).getImage(stack); + + // THEN + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template + .Parameters; + expect( + Object.entries(parameters).some( + ([k, v]) => + k.startsWith('SsmParameterValue') && + (v as any).Default.includes( + '/ecs/optimized-ami/amazon-linux-2/kernel-5.10/', + ), + ), + ).toEqual(true); + }); + + test('Amazon Linux 2 ARM with kernel 5.10', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + + // WHEN + ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.ARM, { + kernel: ecs.AmiLinuxKernelVersion.KERNEL_5_10, + }).getImage(stack); + + // THEN + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template + .Parameters; + expect( + Object.entries(parameters).some( + ([k, v]) => + k.startsWith('SsmParameterValue') && + (v as any).Default.includes( + '/ecs/optimized-ami/amazon-linux-2/kernel-5.10/arm64/', + ), + ), + ).toEqual(true); + }); + + test('Amazon Linux 2 GPU with kernel 5.10', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + + // WHEN + ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.GPU, { + kernel: ecs.AmiLinuxKernelVersion.KERNEL_5_10, + }).getImage(stack); + + // THEN + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template + .Parameters; + expect( + Object.entries(parameters).some( + ([k, v]) => + k.startsWith('SsmParameterValue') && + (v as any).Default.includes( + '/ecs/optimized-ami/amazon-linux-2/kernel-5.10/gpu/', + ), + ), + ).toEqual(true); + }); + + test('Amazon Linux 2 Neuron with kernel 5.10', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app); + + // WHEN + ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.NEURON, { + kernel: ecs.AmiLinuxKernelVersion.KERNEL_5_10, + }).getImage(stack); + + // THEN + const assembly = app.synth(); + const parameters = assembly.getStackByName(stack.stackName).template + .Parameters; + expect( + Object.entries(parameters).some( + ([k, v]) => + k.startsWith('SsmParameterValue') && + (v as any).Default.includes( + '/ecs/optimized-ami/amazon-linux-2/kernel-5.10/inf/', + ), + ), + ).toEqual(true); + }); + + // Testing incompatible combinations using the deprecated EcsOptimizedAmi class + // since we can't access the private constructor of EcsOptimizedImage directly + test('Error when specifying both windowsVersion and windowsCoreVersion', () => { + // WHEN/THEN - using the deprecated class for testing validation + expect(() => { + new ecs.EcsOptimizedAmi({ + windowsVersion: ecs.WindowsOptimizedVersion.SERVER_2019, + windowsCoreVersion: ecs.WindowsOptimizedCoreVersion.SERVER_2019_CORE, + }); + }).toThrow(/Cannot specify both windowsVersion and windowsCoreVersion/); + }); + + test('Error when specifying Windows with special hardware types', () => { + // WHEN/THEN - using the deprecated class for testing validation + expect(() => { + new ecs.EcsOptimizedAmi({ + windowsVersion: ecs.WindowsOptimizedVersion.SERVER_2019, + hardwareType: ecs.AmiHardwareType.GPU, + }); + }).toThrow(/does not support special hardware type/); + }); + + test('Error when specifying Windows Core with special hardware types', () => { + // WHEN/THEN - using the deprecated class for testing validation + expect(() => { + new ecs.EcsOptimizedAmi({ + windowsCoreVersion: ecs.WindowsOptimizedCoreVersion.SERVER_2019_CORE, + hardwareType: ecs.AmiHardwareType.ARM, + }); + }).toThrow(/does not support special hardware type/); }); });