From 5ad3ccd84eeef425588f26d49feb32931d0473d1 Mon Sep 17 00:00:00 2001 From: ahmetsoykan Date: Sun, 11 Feb 2024 23:12:46 +0100 Subject: [PATCH] fix(aws-autoscaling-hooktargets): passing parent construct id to the topic which will be created with addLifecycleHook function of ASG --- .../test/integ.role-target-hook.ts | 2 +- .../aws-ecs-integ-ecs.assets.json | 6 +- .../aws-ecs-integ-ecs.template.json | 94 ++--- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 40 +- ...efaultTestDeployAssertF02313CA.assets.json | 2 +- .../tree.json | 124 +++--- .../aws-ecs-integ-appmesh-proxy.assets.json | 6 +- .../aws-ecs-integ-appmesh-proxy.template.json | 144 +++---- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 39 +- .../tree.json | 194 +++++---- .../aws-ecs-integ-bottlerocket.assets.json | 6 +- .../aws-ecs-integ-bottlerocket.template.json | 138 +++---- .../integ.bottlerocket.js.snapshot/cdk.out | 2 +- .../integ.bottlerocket.js.snapshot/integ.json | 2 +- .../manifest.json | 39 +- .../integ.bottlerocket.js.snapshot/tree.json | 166 ++++---- .../cdk.out | 2 +- .../integ-ec2-capacity-provider.assets.json | 6 +- .../integ-ec2-capacity-provider.template.json | 144 +++---- .../integ.json | 2 +- .../manifest.json | 39 +- .../tree.json | 174 ++++---- .../aws-ecs-integ.assets.json | 6 +- .../aws-ecs-integ.template.json | 162 ++++---- .../ec2/integ.clb-host-nw.js.snapshot/cdk.out | 2 +- .../integ.clb-host-nw.js.snapshot/integ.json | 2 +- .../manifest.json | 39 +- .../integ.clb-host-nw.js.snapshot/tree.json | 190 ++++----- .../aws-ecs-integ.assets.json | 6 +- .../aws-ecs-integ.template.json | 88 ++--- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 41 +- .../tree.json | 116 +++--- ...efaultTestDeployAssert30F9785A.assets.json | 2 +- .../cdk.out | 2 +- ...nteg-default-capacity-provider.assets.json | 6 +- ...eg-default-capacity-provider.template.json | 14 +- .../integ.json | 2 +- .../manifest.json | 43 +- .../tree.json | 374 +++++++++--------- ...efaultTestDeployAssertAFB973D1.assets.json | 2 +- .../__entrypoint__.js | 147 ------- .../index.js | 81 ---- .../__entrypoint__.js | 147 +++++++ .../index.js | 1 + .../cdk.out | 2 +- .../integ-deployment-alarms.assets.json | 12 +- .../integ-deployment-alarms.template.json | 16 +- .../integ.json | 2 +- .../manifest.json | 45 ++- .../tree.json | 38 +- .../aws-ecs-integ.assets.json | 4 +- .../aws-ecs-integ.template.json | 14 +- .../manifest.json | 46 ++- .../tree.json | 30 +- .../aws-ecs-integ-exec-command.assets.json | 6 +- .../aws-ecs-integ-exec-command.template.json | 144 +++---- .../integ.exec-command.js.snapshot/cdk.out | 2 +- .../integ.exec-command.js.snapshot/integ.json | 2 +- .../manifest.json | 39 +- .../integ.exec-command.js.snapshot/tree.json | 172 ++++---- .../aws-ecs-integ.assets.json | 6 +- .../aws-ecs-integ.template.json | 144 +++---- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 39 +- .../tree.json | 182 +++++---- .../aws-ecs-integ.assets.json | 6 +- .../aws-ecs-integ.template.json | 144 +++---- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 39 +- .../tree.json | 172 ++++---- .../aws-ecs-integ.assets.json | 6 +- .../aws-ecs-integ.template.json | 144 +++---- .../ec2/integ.graviton.js.snapshot/cdk.out | 2 +- .../ec2/integ.graviton.js.snapshot/integ.json | 2 +- .../integ.graviton.js.snapshot/manifest.json | 39 +- .../ec2/integ.graviton.js.snapshot/tree.json | 172 ++++---- .../aws-ecs-integ.assets.json | 6 +- .../aws-ecs-integ.template.json | 170 ++++---- .../integ.lb-awsvpc-nw.js.snapshot/cdk.out | 2 +- .../integ.lb-awsvpc-nw.js.snapshot/integ.json | 2 +- .../manifest.json | 39 +- .../integ.lb-awsvpc-nw.js.snapshot/tree.json | 200 +++++----- .../aws-ecs-integ-ecs.assets.json | 6 +- .../aws-ecs-integ-ecs.template.json | 160 ++++---- .../integ.lb-bridge-nw.js.snapshot/cdk.out | 2 +- .../integ.lb-bridge-nw.js.snapshot/integ.json | 2 +- .../manifest.json | 39 +- .../integ.lb-bridge-nw.js.snapshot/tree.json | 188 ++++----- ...cdk-ecs-integration-test-stack.assets.json | 6 +- ...k-ecs-integration-test-stack.template.json | 144 +++---- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 39 +- .../tree.json | 172 ++++---- ...efaultTestDeployAssert1B88B826.assets.json | 2 +- .../aws-ecs-integ-pseudo-terminal.assets.json | 6 +- ...ws-ecs-integ-pseudo-terminal.template.json | 144 +++---- .../integ.pseudo-terminal.js.snapshot/cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 40 +- .../tree.json | 184 +++++---- .../aws-ecs-integ-ecs.assets.json | 6 +- .../aws-ecs-integ-ecs.template.json | 144 +++---- .../integ.sd-awsvpc-nw.js.snapshot/cdk.out | 2 +- .../integ.sd-awsvpc-nw.js.snapshot/integ.json | 2 +- .../manifest.json | 39 +- .../integ.sd-awsvpc-nw.js.snapshot/tree.json | 180 +++++---- .../aws-ecs-integ-ecs.assets.json | 6 +- .../aws-ecs-integ-ecs.template.json | 144 +++---- .../integ.sd-bridge-nw.js.snapshot/cdk.out | 2 +- .../integ.sd-bridge-nw.js.snapshot/integ.json | 2 +- .../manifest.json | 39 +- .../integ.sd-bridge-nw.js.snapshot/tree.json | 172 ++++---- .../aws-ecs-integ-spot.assets.json | 6 +- .../aws-ecs-integ-spot.template.json | 28 +- .../ec2/integ.spot-drain.js.snapshot/cdk.out | 2 +- .../integ.spot-drain.js.snapshot/integ.json | 2 +- .../manifest.json | 82 +++- .../integ.spot-drain.js.snapshot/tree.json | 66 ++-- ...efaultTestDeployAssert4CDF4940.assets.json | 2 +- .../aws-ecs-integ.assets.json | 6 +- .../aws-ecs-integ.template.json | 144 +++---- .../integ.swap-parameters.js.snapshot/cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 40 +- .../tree.json | 174 ++++---- .../__entrypoint__.js | 147 ------- .../index.js | 81 ---- .../__entrypoint__.js | 147 +++++++ .../index.js | 1 + ...cdk-ecs-integration-test-stack.assets.json | 12 +- ...k-ecs-integration-test-stack.template.json | 16 +- ...efaultTestDeployAssert906A0CF3.assets.json | 2 +- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 45 ++- .../tree.json | 38 +- .../integ-ecs-neuron-ami.assets.json | 4 +- .../integ-ecs-neuron-ami.template.json | 14 +- .../manifest.json | 41 +- .../tree.json | 30 +- ...-integ-bottlerocket-nvidia-ami.assets.json | 4 +- ...nteg-bottlerocket-nvidia-ami.template.json | 14 +- .../manifest.json | 41 +- .../tree.json | 30 +- ...efaultTestDeployAssert8B2741C4.assets.json | 2 +- .../aws-ecs-integ-ecs.assets.json | 6 +- .../aws-ecs-integ-ecs.template.json | 94 ++--- .../integ.event-ec2-task.js.snapshot/cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 40 +- .../tree.json | 124 +++--- .../aws-sfn-tasks-ecs-ec2-integ.assets.json | 6 +- .../aws-sfn-tasks-ecs-ec2-integ.template.json | 156 ++++---- .../integ.ec2-run-task.js.snapshot/cdk.out | 2 +- .../integ.ec2-run-task.js.snapshot/integ.json | 2 +- .../manifest.json | 39 +- .../integ.ec2-run-task.js.snapshot/tree.json | 184 ++++----- .../aws-ecs-integ2.assets.json | 6 +- .../aws-ecs-integ2.template.json | 156 ++++---- .../ecs/integ.ec2-task.js.snapshot/cdk.out | 2 +- .../ecs/integ.ec2-task.js.snapshot/integ.json | 2 +- .../integ.ec2-task.js.snapshot/manifest.json | 39 +- .../ecs/integ.ec2-task.js.snapshot/tree.json | 184 ++++----- .../lib/lambda-hook.ts | 6 +- .../lib/queue-hook.ts | 2 +- .../lib/topic-hook.ts | 2 +- .../test/hooks.test.ts | 12 +- .../lib/lifecycle-hook-target.ts | 2 +- .../aws-autoscaling/lib/lifecycle-hook.ts | 2 +- .../test/lifecyclehooks.test.ts | 2 +- .../aws-cdk-lib/aws-ecs/test/cluster.test.ts | 2 +- 180 files changed, 4896 insertions(+), 4243 deletions(-) delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/__entrypoint__.js delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/index.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/__entrypoint__.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/index.js delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/__entrypoint__.js delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/index.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/__entrypoint__.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/index.js diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.role-target-hook.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.role-target-hook.ts index 80bc313c60dda..0a7cc92bfd4d1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.role-target-hook.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.role-target-hook.ts @@ -20,7 +20,7 @@ export class FakeNotificationTarget implements autoscaling.ILifecycleHookTarget return role; } - public bind(_scope: constructs.Construct, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { + public bind(_scope: constructs.Construct, _id: string, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { const role = this.createRole(options.lifecycleHook, options.role); this.topic.grantPublish(role); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/aws-ecs-integ-ecs.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/aws-ecs-integ-ecs.assets.json index e363ac0d0b6eb..29d26d6b0975f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/aws-ecs-integ-ecs.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/aws-ecs-integ-ecs.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "4c0df9ce23bee909471dcd6f95f00eb098e38a732aaa6e3a15f82a7845af7f2f": { + "29d88221f45f5544092a53f3ff08e9b8f2a4c5104289c49c238980b499f53664": { "source": { "path": "aws-ecs-integ-ecs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "4c0df9ce23bee909471dcd6f95f00eb098e38a732aaa6e3a15f82a7845af7f2f.json", + "objectKey": "29d88221f45f5544092a53f3ff08e9b8f2a4c5104289c49c238980b499f53664.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/aws-ecs-integ-ecs.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/aws-ecs-integ-ecs.template.json index 839a70bfb25bf..f2807cf3e764c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/aws-ecs-integ-ecs.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/aws-ecs-integ-ecs.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -183,12 +183,12 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -206,11 +206,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -412,8 +412,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -425,6 +423,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -577,12 +577,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -591,6 +585,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -605,7 +605,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -617,26 +617,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -679,7 +679,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -699,11 +699,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/cdk.out index f0b901e7c06e5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/integ.json index 487856705c10c..ac2fab21b40a0 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "scheduledEc2TaskTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/manifest.json index 553edcaaa5938..173627828c469 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-ecs.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-ecs.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}/4c0df9ce23bee909471dcd6f95f00eb098e38a732aaa6e3a15f82a7845af7f2f.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/29d88221f45f5544092a53f3ff08e9b8f2a4c5104289c49c238980b499f53664.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -171,22 +172,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -273,10 +274,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] @@ -298,6 +317,7 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "scheduledEc2TaskTestDefaultTestDeployAssertF02313CA.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}", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/scheduledEc2TaskTestDefaultTestDeployAssertF02313CA.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/scheduledEc2TaskTestDefaultTestDeployAssertF02313CA.assets.json index 1f8ccb07d3175..61bf10763057e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/scheduledEc2TaskTestDefaultTestDeployAssertF02313CA.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/scheduledEc2TaskTestDefaultTestDeployAssertF02313CA.assets.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/tree.json index f0594943fea01..13b51fb4c0baa 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs-patterns/test/ec2/integ.scheduled-ecs-task.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -346,11 +346,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -568,6 +568,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -667,8 +675,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -680,6 +686,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -884,12 +892,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -898,6 +900,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -913,9 +921,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": { - "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", + "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": { + "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -928,7 +936,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -937,25 +945,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -979,20 +987,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1074,7 +1082,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1114,11 +1122,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1604,7 +1612,7 @@ "path": "scheduledEc2TaskTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "DeployAssert": { @@ -1650,7 +1658,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/aws-ecs-integ-appmesh-proxy.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/aws-ecs-integ-appmesh-proxy.assets.json index d5d36c7a61256..fca97bab3f6fd 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/aws-ecs-integ-appmesh-proxy.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/aws-ecs-integ-appmesh-proxy.assets.json @@ -1,7 +1,7 @@ { - "version": "31.0.0", + "version": "36.0.0", "files": { - "679dcaa7707c9ab2ca704cc7a9637bec0c4c5ce0f7bdb0605d6ebd5f5de37dd9": { + "7aa2b6da7aa22a975c5dc9961d9cf11eca317ff7daad96ec972182338330d572": { "source": { "path": "aws-ecs-integ-appmesh-proxy.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "679dcaa7707c9ab2ca704cc7a9637bec0c4c5ce0f7bdb0605d6ebd5f5de37dd9.json", + "objectKey": "7aa2b6da7aa22a975c5dc9961d9cf11eca317ff7daad96ec972182338330d572.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/aws-ecs-integ-appmesh-proxy.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/aws-ecs-integ-appmesh-proxy.template.json index 4abdf05274bdf..6ad1a030931a1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/aws-ecs-integ-appmesh-proxy.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/aws-ecs-integ-appmesh-proxy.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-appmesh-proxy/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-appmesh-proxy/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-appmesh-proxy/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-appmesh-proxy/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ-appmesh-proxy/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-appmesh-proxy/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ-appmesh-proxy/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-appmesh-proxy/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -589,8 +589,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic6486DB9E6F5E487C": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5AB393C73F45306D": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/cdk.out index 0d5aff521d3a2..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"31.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/integ.json index 1571141d949dc..4e4e0345bfe3f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "31.0.0", + "version": "36.0.0", "testCases": { "integ.app-mesh-proxy-config": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/manifest.json index 7bc51092348b0..6bea273b85de9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "31.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-appmesh-proxy.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-appmesh-proxy.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}/679dcaa7707c9ab2ca704cc7a9637bec0c4c5ce0f7bdb0605d6ebd5f5de37dd9.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/7aa2b6da7aa22a975c5dc9961d9cf11eca317ff7daad96ec972182338330d572.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic6486DB9E": [ + "/aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5AB393C7": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic6486DB9E6F5E487C" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5AB393C73F45306D" } ], - "/aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -309,10 +310,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic6486DB9E6F5E487C": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic6486DB9E6F5E487C", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/tree.json index 206d4489fbd90..1c6f51337e3a4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.app-mesh-proxy-config.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-appmesh-proxy/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-appmesh-proxy/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-appmesh-proxy/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-appmesh-proxy/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ-appmesh-proxy/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-appmesh-proxy/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ-appmesh-proxy/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-appmesh-proxy/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -943,7 +951,7 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_autoscaling.CfnLaunchConfiguration", + "fqn": "aws-cdk-lib.aws_ec2.LaunchTemplate", "version": "0.0.0" } }, @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic6486DB9E": { - "id": "AllowInvoke:awsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic6486DB9E", - "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic6486DB9E", + "AllowInvoke:awsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5AB393C7": { + "id": "AllowInvoke:awsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5AB393C7", + "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegappmeshproxyEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5AB393C7", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-appmesh-proxy/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1514,13 +1522,29 @@ "essential": true, "image": "amazon/amazon-ecs-sample", "memory": 256, - "name": "web" + "name": "web", + "environment": [ + { + "name": "AWS_REGION", + "value": { + "Ref": "AWS::Region" + } + } + ] }, { "essential": true, "image": "envoyproxy/envoy:v1.16.2", "memory": 256, - "name": "envoy" + "name": "envoy", + "environment": [ + { + "name": "AWS_REGION", + "value": { + "Ref": "AWS::Region" + } + } + ] } ], "family": "awsecsintegappmeshproxyTaskDef1D8BFD08", @@ -1714,7 +1738,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/aws-ecs-integ-bottlerocket.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/aws-ecs-integ-bottlerocket.assets.json index f4e0a0acd0558..c5baceec43683 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/aws-ecs-integ-bottlerocket.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/aws-ecs-integ-bottlerocket.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "23efb012af109a2b701accba88ab31415b5012b2ff3ce7c0de38ee461130c4a3": { + "d111f0c8ab8421a032b9017c604935559995cd7763564f4b2735bd6f12227726": { "source": { "path": "aws-ecs-integ-bottlerocket.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "23efb012af109a2b701accba88ab31415b5012b2ff3ce7c0de38ee461130c4a3.json", + "objectKey": "d111f0c8ab8421a032b9017c604935559995cd7763564f4b2735bd6f12227726.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/aws-ecs-integ-bottlerocket.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/aws-ecs-integ-bottlerocket.template.json index d01c94ae611e3..03b9559fddc84 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/aws-ecs-integ-bottlerocket.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/aws-ecs-integ-bottlerocket.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-bottlerocket/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-bottlerocket/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-bottlerocket/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-bottlerocket/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -198,9 +198,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -224,21 +221,24 @@ "Key": "Name", "Value": "aws-ecs-integ-bottlerocket/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-bottlerocket/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -255,21 +255,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -293,21 +290,24 @@ "Key": "Name", "Value": "aws-ecs-integ-bottlerocket/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-bottlerocket/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -324,12 +324,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -347,11 +347,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -579,8 +579,6 @@ "EcsClusterbottlerocketasgASGCB222A6E": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "2", - "MinSize": "2", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterbottlerocketasgLaunchTemplateE141ADC4" @@ -592,6 +590,8 @@ ] } }, + "MaxSize": "2", + "MinSize": "2", "Tags": [ { "Key": "Name", @@ -747,12 +747,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterbottlerocketasgDrainECSHookFunctionServiceRole2F16AFAB", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -761,6 +755,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterbottlerocketasgDrainECSHookFunctionServiceRole2F16AFAB", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -775,7 +775,7 @@ "EcsClusterbottlerocketasgDrainECSHookFunctionServiceRole2F16AFAB" ] }, - "EcsClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicD05837A873EBB93D": { + "EcsClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookE497A98617281619": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -787,26 +787,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" + "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" } } }, - "EcsClusterbottlerocketasgDrainECSHookFunctionTopic1953D6F0": { + "EcsClusterbottlerocketasgDrainECSHookFunctionTopicLifecycleHookDrainHook4CDDCFC2": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterbottlerocketasgDrainECSHookFunction7A8CD0E4", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" } } }, - "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74": { + "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -849,7 +849,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" + "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" } } ], @@ -869,11 +869,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterbottlerocketasgASGCB222A6E" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" + "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/cdk.out index f0b901e7c06e5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/integ.json index b22af7950be85..89303cd43f30b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.bottlerocket": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/manifest.json index 55d74778bdfca..4c49907fc0ba7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-bottlerocket.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-bottlerocket.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}/23efb012af109a2b701accba88ab31415b5012b2ff3ce7c0de38ee461130c4a3.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/d111f0c8ab8421a032b9017c604935559995cd7763564f4b2735bd6f12227726.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -219,22 +220,22 @@ "data": "EcsClusterbottlerocketasgDrainECSHookFunction7A8CD0E4" } ], - "/aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/AllowInvoke:awsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicD05837A8": [ + "/aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/AllowInvoke:awsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookE497A986": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicD05837A873EBB93D" + "data": "EcsClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookE497A98617281619" } ], - "/aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterbottlerocketasgDrainECSHookFunctionTopic1953D6F0" + "data": "EcsClusterbottlerocketasgDrainECSHookFunctionTopicLifecycleHookDrainHook4CDDCFC2" } ], - "/aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" + "data": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" } ], "/aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LifecycleHookDrainHook/Role/Resource": [ @@ -273,10 +274,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterbottlerocketasgLaunchTemplateProfileF6362A11": [ + "EcsClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicD05837A873EBB93D": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterbottlerocketasgLaunchTemplateProfileF6362A11", + "data": "EcsClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicD05837A873EBB93D", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterbottlerocketasgDrainECSHookFunctionTopic1953D6F0": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterbottlerocketasgDrainECSHookFunctionTopic1953D6F0", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/tree.json index 0f99812c1ab0d..9391a93e9ca3a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.bottlerocket.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-bottlerocket/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-bottlerocket/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-bottlerocket/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-bottlerocket/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -331,9 +331,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -357,7 +354,10 @@ "key": "Name", "value": "aws-ecs-integ-bottlerocket/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -379,15 +379,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-bottlerocket/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -420,12 +420,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -450,9 +450,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -476,7 +473,10 @@ "key": "Name", "value": "aws-ecs-integ-bottlerocket/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -498,15 +498,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-bottlerocket/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -539,12 +539,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -584,11 +584,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -832,6 +832,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LaunchTemplate", @@ -931,8 +939,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "2", - "minSize": "2", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterbottlerocketasgLaunchTemplateE141ADC4" @@ -944,6 +950,8 @@ ] } }, + "maxSize": "2", + "minSize": "2", "tags": [ { "key": "Name", @@ -1151,12 +1159,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterbottlerocketasgDrainECSHookFunctionServiceRole2F16AFAB", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1165,6 +1167,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterbottlerocketasgDrainECSHookFunctionServiceRole2F16AFAB", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1180,9 +1188,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicD05837A8": { - "id": "AllowInvoke:awsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicD05837A8", - "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/AllowInvoke:awsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicD05837A8", + "AllowInvoke:awsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookE497A986": { + "id": "AllowInvoke:awsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookE497A986", + "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/AllowInvoke:awsecsintegbottlerocketEcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookE497A986", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1195,7 +1203,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" + "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" } } }, @@ -1204,25 +1212,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterbottlerocketasgDrainECSHookFunction7A8CD0E4", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" } } }, @@ -1246,20 +1254,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-bottlerocket/EcsCluster/bottlerocket-asg/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1341,7 +1349,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" + "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" } } ], @@ -1381,11 +1389,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterbottlerocketasgASGCB222A6E" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopic64509A74" + "Ref": "EcsClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookD97CAD03" }, "roleArn": { "Fn::GetAtt": [ @@ -1461,7 +1469,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/cdk.out index 0d5aff521d3a2..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"31.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ-ec2-capacity-provider.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ-ec2-capacity-provider.assets.json index c7f2b6df241d2..395e9531687e7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ-ec2-capacity-provider.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ-ec2-capacity-provider.assets.json @@ -1,7 +1,7 @@ { - "version": "31.0.0", + "version": "36.0.0", "files": { - "8198483ca83787e1c21f34f0845258f2c1b0f92131f256d5dfefdbddbe142197": { + "dd99a47f08bc5e7ca594c9d70167a03be53477ff0694012dc954edbd1a6c0eb8": { "source": { "path": "integ-ec2-capacity-provider.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "8198483ca83787e1c21f34f0845258f2c1b0f92131f256d5dfefdbddbe142197.json", + "objectKey": "dd99a47f08bc5e7ca594c9d70167a03be53477ff0694012dc954edbd1a6c0eb8.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ-ec2-capacity-provider.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ-ec2-capacity-provider.template.json index 5d6a0c2b0c743..b0e0ffe30b64b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ-ec2-capacity-provider.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ-ec2-capacity-provider.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "integ-ec2-capacity-provider/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "integ-ec2-capacity-provider/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "integ-ec2-capacity-provider/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "integ-ec2-capacity-provider/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "integ-ec2-capacity-provider/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "integ-ec2-capacity-provider/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "integ-ec2-capacity-provider/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "integ-ec2-capacity-provider/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -646,8 +646,6 @@ "ASG46ED3070": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "ASGLaunchTemplate0CA92847" @@ -659,6 +657,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -811,12 +811,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "ASGDrainECSHookFunctionServiceRoleC12963BB", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -825,6 +819,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "ASGDrainECSHookFunctionServiceRoleC12963BB", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -839,7 +839,7 @@ "ASGDrainECSHookFunctionServiceRoleC12963BB" ] }, - "ASGDrainECSHookFunctionAllowInvokeintegec2capacityproviderASGLifecycleHookDrainHookTopic4714B3C1EB63E78F": { + "ASGDrainECSHookFunctionAllowInvokeintegec2capacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook4DC4C606AC968A68": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -851,26 +851,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, - "ASGDrainECSHookFunctionTopicD6FC59F7": { + "ASGDrainECSHookFunctionTopicLifecycleHookDrainHook8B240409": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" - }, "Endpoint": { "Fn::GetAtt": [ "ASGDrainECSHookFunction5F24CF4D", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, - "ASGLifecycleHookDrainHookTopicA8AD4ACB": { + "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -913,7 +913,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } ], @@ -933,11 +933,11 @@ "AutoScalingGroupName": { "Ref": "ASG46ED3070" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ.json index 61a8ebb3a71f3..31dc105e078d1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "31.0.0", + "version": "36.0.0", "testCases": { "integ.capacity-provider": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/manifest.json index 9a5e44ad8172b..acef34547ae60 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "31.0.0", + "version": "36.0.0", "artifacts": { "integ-ec2-capacity-provider.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "integ-ec2-capacity-provider.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}/8198483ca83787e1c21f34f0845258f2c1b0f92131f256d5dfefdbddbe142197.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/dd99a47f08bc5e7ca594c9d70167a03be53477ff0694012dc954edbd1a6c0eb8.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -249,22 +250,22 @@ "data": "ASGDrainECSHookFunction5F24CF4D" } ], - "/integ-ec2-capacity-provider/ASG/DrainECSHook/Function/AllowInvoke:integec2capacityproviderASGLifecycleHookDrainHookTopic4714B3C1": [ + "/integ-ec2-capacity-provider/ASG/DrainECSHook/Function/AllowInvoke:integec2capacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook4DC4C606": [ { "type": "aws:cdk:logicalId", - "data": "ASGDrainECSHookFunctionAllowInvokeintegec2capacityproviderASGLifecycleHookDrainHookTopic4714B3C1EB63E78F" + "data": "ASGDrainECSHookFunctionAllowInvokeintegec2capacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook4DC4C606AC968A68" } ], - "/integ-ec2-capacity-provider/ASG/DrainECSHook/Function/Topic/Resource": [ + "/integ-ec2-capacity-provider/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ASGDrainECSHookFunctionTopicD6FC59F7" + "data": "ASGDrainECSHookFunctionTopicLifecycleHookDrainHook8B240409" } ], - "/integ-ec2-capacity-provider/ASG/LifecycleHookDrainHook/Topic/Resource": [ + "/integ-ec2-capacity-provider/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "data": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } ], "/integ-ec2-capacity-provider/ASG/LifecycleHookDrainHook/Role/Resource": [ @@ -315,10 +316,28 @@ "data": "CheckBootstrapVersion" } ], - "ASGLaunchTemplateProfileB99C522F": [ + "ASGDrainECSHookFunctionAllowInvokeintegec2capacityproviderASGLifecycleHookDrainHookTopic4714B3C1EB63E78F": [ { "type": "aws:cdk:logicalId", - "data": "ASGLaunchTemplateProfileB99C522F", + "data": "ASGDrainECSHookFunctionAllowInvokeintegec2capacityproviderASGLifecycleHookDrainHookTopic4714B3C1EB63E78F", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ASGDrainECSHookFunctionTopicD6FC59F7": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGDrainECSHookFunctionTopicD6FC59F7", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ASGLifecycleHookDrainHookTopicA8AD4ACB": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGLifecycleHookDrainHookTopicA8AD4ACB", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/tree.json index e85549e2bddf3..4e85fda0cbe47 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.capacity-provider.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "integ-ec2-capacity-provider/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "integ-ec2-capacity-provider/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "integ-ec2-capacity-provider/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "integ-ec2-capacity-provider/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "integ-ec2-capacity-provider/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "integ-ec2-capacity-provider/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "integ-ec2-capacity-provider/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "integ-ec2-capacity-provider/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -977,6 +977,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "integ-ec2-capacity-provider/ASG/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "integ-ec2-capacity-provider/ASG/LaunchTemplate", @@ -1066,7 +1074,7 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_autoscaling.CfnLaunchConfiguration", + "fqn": "aws-cdk-lib.aws_ec2.LaunchTemplate", "version": "0.0.0" } }, @@ -1076,8 +1084,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "ASGLaunchTemplate0CA92847" @@ -1089,6 +1095,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1296,12 +1304,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "ASGDrainECSHookFunctionServiceRoleC12963BB", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1310,6 +1312,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "ASGDrainECSHookFunctionServiceRoleC12963BB", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1325,9 +1333,9 @@ "version": "0.0.0" } }, - "AllowInvoke:integec2capacityproviderASGLifecycleHookDrainHookTopic4714B3C1": { - "id": "AllowInvoke:integec2capacityproviderASGLifecycleHookDrainHookTopic4714B3C1", - "path": "integ-ec2-capacity-provider/ASG/DrainECSHook/Function/AllowInvoke:integec2capacityproviderASGLifecycleHookDrainHookTopic4714B3C1", + "AllowInvoke:integec2capacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook4DC4C606": { + "id": "AllowInvoke:integec2capacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook4DC4C606", + "path": "integ-ec2-capacity-provider/ASG/DrainECSHook/Function/AllowInvoke:integec2capacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook4DC4C606", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1340,7 +1348,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, @@ -1349,25 +1357,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "integ-ec2-capacity-provider/ASG/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "integ-ec2-capacity-provider/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "integ-ec2-capacity-provider/ASG/DrainECSHook/Function/Topic/Resource", + "path": "integ-ec2-capacity-provider/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" - }, "endpoint": { "Fn::GetAtt": [ "ASGDrainECSHookFunction5F24CF4D", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, @@ -1391,20 +1399,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "integ-ec2-capacity-provider/ASG/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "integ-ec2-capacity-provider/ASG/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "integ-ec2-capacity-provider/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "integ-ec2-capacity-provider/ASG/LifecycleHookDrainHook/Topic/Resource", + "path": "integ-ec2-capacity-provider/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1486,7 +1494,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } ], @@ -1526,11 +1534,11 @@ "autoScalingGroupName": { "Ref": "ASG46ED3070" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" }, "roleArn": { "Fn::GetAtt": [ @@ -1681,7 +1689,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/aws-ecs-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/aws-ecs-integ.assets.json index 0d01539c2653f..e1450acbb6533 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/aws-ecs-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/aws-ecs-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "3b6e5fdbab22f0c2355ff6ada6048f5dc03cbaf873a46da976e9b5bbcafab392": { + "cba0a8e97f9c7f3930a27915f0532d394277a3fb2eb9280e9d45a276b634fb8f": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "3b6e5fdbab22f0c2355ff6ada6048f5dc03cbaf873a46da976e9b5bbcafab392.json", + "objectKey": "cba0a8e97f9c7f3930a27915f0532d394277a3fb2eb9280e9d45a276b634fb8f.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/aws-ecs-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/aws-ecs-integ.template.json index 166852a75e8d2..1c942c80dfa09 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/aws-ecs-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/aws-ecs-integ.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -419,7 +419,6 @@ "EcsClusterDefaultAutoScalingGroupInstanceSecurityGroupfromawsecsintegLBSecurityGroupC30F5EB480A6611BD8": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { - "IpProtocol": "tcp", "Description": "Port 80 LB to fleet", "FromPort": 80, "GroupId": { @@ -428,6 +427,7 @@ "GroupId" ] }, + "IpProtocol": "tcp", "SourceSecurityGroupId": { "Fn::GetAtt": [ "LBSecurityGroup8A41EA2B", @@ -610,8 +610,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -623,6 +621,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -778,12 +778,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -792,6 +786,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -806,7 +806,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -818,26 +818,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -880,7 +880,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -900,11 +900,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ @@ -1024,13 +1024,6 @@ "LBSecurityGrouptoawsecsintegEcsClusterDefaultAutoScalingGroupInstanceSecurityGroupF03D24578019AB9BA2": { "Type": "AWS::EC2::SecurityGroupEgress", "Properties": { - "GroupId": { - "Fn::GetAtt": [ - "LBSecurityGroup8A41EA2B", - "GroupId" - ] - }, - "IpProtocol": "tcp", "Description": "Port 80 LB to fleet", "DestinationSecurityGroupId": { "Fn::GetAtt": [ @@ -1039,12 +1032,20 @@ ] }, "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "LBSecurityGroup8A41EA2B", + "GroupId" + ] + }, + "IpProtocol": "tcp", "ToPort": 80 } }, "LB8A12904C": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { + "CrossZone": true, "Listeners": [ { "InstancePort": "80", @@ -1053,7 +1054,6 @@ "Protocol": "http" } ], - "CrossZone": true, "Scheme": "internal", "SecurityGroups": [ { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/integ.json index 5330e3da12318..01bee4cfbf5a5 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.clb-host-nw": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/manifest.json index f67399ea25a64..06457c372443d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ.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}/3b6e5fdbab22f0c2355ff6ada6048f5dc03cbaf873a46da976e9b5bbcafab392.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/cba0a8e97f9c7f3930a27915f0532d394277a3fb2eb9280e9d45a276b634fb8f.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -237,22 +238,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -333,10 +334,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/tree.json index 87e809b900964..e90ab3d64fa17 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.clb-host-nw.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -711,7 +711,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupIngress", "aws:cdk:cloudformation:props": { - "ipProtocol": "tcp", "description": "Port 80 LB to fleet", "fromPort": 80, "groupId": { @@ -720,6 +719,7 @@ "GroupId" ] }, + "ipProtocol": "tcp", "sourceSecurityGroupId": { "Fn::GetAtt": [ "LBSecurityGroup8A41EA2B", @@ -883,6 +883,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -982,8 +990,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -995,6 +1001,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1202,12 +1210,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1216,6 +1218,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1231,9 +1239,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": { - "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", + "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": { + "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1246,7 +1254,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1255,25 +1263,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1297,20 +1305,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1392,7 +1400,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1432,11 +1440,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1677,13 +1685,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupEgress", "aws:cdk:cloudformation:props": { - "groupId": { - "Fn::GetAtt": [ - "LBSecurityGroup8A41EA2B", - "GroupId" - ] - }, - "ipProtocol": "tcp", "description": "Port 80 LB to fleet", "destinationSecurityGroupId": { "Fn::GetAtt": [ @@ -1692,6 +1693,13 @@ ] }, "fromPort": 80, + "groupId": { + "Fn::GetAtt": [ + "LBSecurityGroup8A41EA2B", + "GroupId" + ] + }, + "ipProtocol": "tcp", "toPort": 80 } }, @@ -1712,6 +1720,7 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::ElasticLoadBalancing::LoadBalancer", "aws:cdk:cloudformation:props": { + "crossZone": true, "listeners": [ { "loadBalancerPort": "80", @@ -1720,7 +1729,6 @@ "instanceProtocol": "http" } ], - "crossZone": true, "scheme": "internal", "securityGroups": [ { @@ -1786,7 +1794,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/aws-ecs-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/aws-ecs-integ.assets.json index c6f1e975eaf74..5a2163db8f58d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/aws-ecs-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/aws-ecs-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "2137214b2de0d9d04157ab2368c4092ca0702af5ebf8a6baeadddb73e300f629": { + "619b4cc023a42a57207323be8670525dd4b0901fcec645081595124c3d965f1d": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "2137214b2de0d9d04157ab2368c4092ca0702af5ebf8a6baeadddb73e300f629.json", + "objectKey": "619b4cc023a42a57207323be8670525dd4b0901fcec645081595124c3d965f1d.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/aws-ecs-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/aws-ecs-integ.template.json index 73fbcc26d0e6f..7082d3fcf7865 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/aws-ecs-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/aws-ecs-integ.template.json @@ -18,9 +18,6 @@ "VpcpubSubnet1Subnet410C08CF": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/pubSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcpubSubnet1RouteTableE0483FDA": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/pubSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcpubSubnet1RouteTableAssociation68036D8C": { @@ -75,12 +75,12 @@ "VpcpubSubnet1DefaultRouteF020A9EF": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcpubSubnet1RouteTableE0483FDA" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcpubSubnet1RouteTableE0483FDA" } }, "DependsOn": [ @@ -90,9 +90,6 @@ "VpcpubSubnet2Subnet44A37A0D": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -116,21 +113,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/pubSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcpubSubnet2RouteTable5A29DF40": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/pubSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcpubSubnet2RouteTableAssociationFB826925": { @@ -147,12 +147,12 @@ "VpcpubSubnet2DefaultRouteE6D48BA4": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcpubSubnet2RouteTable5A29DF40" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcpubSubnet2RouteTable5A29DF40" } }, "DependsOn": [ @@ -173,11 +173,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -388,8 +388,6 @@ "FargateClustercapacityASGE4034F96": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "DesiredCapacity": "1", "LaunchTemplate": { "LaunchTemplateId": { @@ -402,6 +400,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -557,12 +557,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "FargateClustercapacityDrainECSHookFunctionServiceRoleA28505D9", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -571,6 +565,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "FargateClustercapacityDrainECSHookFunctionServiceRoleA28505D9", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -585,7 +585,7 @@ "FargateClustercapacityDrainECSHookFunctionServiceRoleA28505D9" ] }, - "FargateClustercapacityDrainECSHookFunctionAllowInvokeawsecsintegFargateClustercapacityLifecycleHookDrainHookTopic07C1229F3B6FF246": { + "FargateClustercapacityDrainECSHookFunctionAllowInvokeawsecsintegFargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHook7BA31FB27B4A9179": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -597,26 +597,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" + "Ref": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" } } }, - "FargateClustercapacityDrainECSHookFunctionTopic7D6C4884": { + "FargateClustercapacityDrainECSHookFunctionTopicLifecycleHookDrainHook6A2BD348": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" - }, "Endpoint": { "Fn::GetAtt": [ "FargateClustercapacityDrainECSHookFunction3E60E6D0", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" } } }, - "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34": { + "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -659,7 +659,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" + "Ref": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" } } ], @@ -679,11 +679,11 @@ "AutoScalingGroupName": { "Ref": "FargateClustercapacityASGE4034F96" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" + "Ref": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/integ.json index 8842e99673c7f..2ea67ba1f9a45 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.cloudmap-container-port": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/manifest.json index 031dedb3d3c71..f8fcee7179466 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ.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}/2137214b2de0d9d04157ab2368c4092ca0702af5ebf8a6baeadddb73e300f629.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/619b4cc023a42a57207323be8670525dd4b0901fcec645081595124c3d965f1d.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -108,7 +109,7 @@ "/aws-ecs-integ/FargateCluster/capacity": [ { "type": "aws:cdk:warning", - "data": "desiredCapacity has been configured. Be aware this will reset the size of your AutoScalingGroup on every deployment. See https://github.com/aws/aws-cdk/issues/5215" + "data": "desiredCapacity has been configured. Be aware this will reset the size of your AutoScalingGroup on every deployment. See https://github.com/aws/aws-cdk/issues/5215 [ack: @aws-cdk/aws-autoscaling:desiredCapacitySet]" } ], "/aws-ecs-integ/FargateCluster/capacity/InstanceSecurityGroup/Resource": [ @@ -165,22 +166,22 @@ "data": "FargateClustercapacityDrainECSHookFunction3E60E6D0" } ], - "/aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/AllowInvoke:awsecsintegFargateClustercapacityLifecycleHookDrainHookTopic07C1229F": [ + "/aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/AllowInvoke:awsecsintegFargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHook7BA31FB2": [ { "type": "aws:cdk:logicalId", - "data": "FargateClustercapacityDrainECSHookFunctionAllowInvokeawsecsintegFargateClustercapacityLifecycleHookDrainHookTopic07C1229F3B6FF246" + "data": "FargateClustercapacityDrainECSHookFunctionAllowInvokeawsecsintegFargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHook7BA31FB27B4A9179" } ], - "/aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "FargateClustercapacityDrainECSHookFunctionTopic7D6C4884" + "data": "FargateClustercapacityDrainECSHookFunctionTopicLifecycleHookDrainHook6A2BD348" } ], - "/aws-ecs-integ/FargateCluster/capacity/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ/FargateCluster/capacity/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" + "data": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" } ], "/aws-ecs-integ/FargateCluster/capacity/LifecycleHookDrainHook/Role/Resource": [ @@ -249,10 +250,28 @@ "data": "CheckBootstrapVersion" } ], - "FargateClustercapacityLaunchTemplateProfile4BF7EF9F": [ + "FargateClustercapacityDrainECSHookFunctionAllowInvokeawsecsintegFargateClustercapacityLifecycleHookDrainHookTopic07C1229F3B6FF246": [ { "type": "aws:cdk:logicalId", - "data": "FargateClustercapacityLaunchTemplateProfile4BF7EF9F", + "data": "FargateClustercapacityDrainECSHookFunctionAllowInvokeawsecsintegFargateClustercapacityLifecycleHookDrainHookTopic07C1229F3B6FF246", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "FargateClustercapacityDrainECSHookFunctionTopic7D6C4884": [ + { + "type": "aws:cdk:logicalId", + "data": "FargateClustercapacityDrainECSHookFunctionTopic7D6C4884", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34": [ + { + "type": "aws:cdk:logicalId", + "data": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/tree.json index 4fa3a53499459..583e3481afc15 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.cloudmap-container-port.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/pubSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/pubSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcpubSubnet1RouteTableE0483FDA" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcpubSubnet1RouteTableE0483FDA" } } }, @@ -164,9 +164,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -190,7 +187,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/pubSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -212,15 +212,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/pubSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -253,12 +253,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcpubSubnet2RouteTable5A29DF40" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcpubSubnet2RouteTable5A29DF40" } } }, @@ -298,11 +298,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -529,6 +529,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ/FargateCluster/capacity/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ/FargateCluster/capacity/LaunchTemplate", @@ -628,8 +636,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "desiredCapacity": "1", "launchTemplate": { "launchTemplateId": { @@ -642,6 +648,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -849,12 +857,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "FargateClustercapacityDrainECSHookFunctionServiceRoleA28505D9", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -863,6 +865,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "FargateClustercapacityDrainECSHookFunctionServiceRoleA28505D9", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -878,9 +886,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegFargateClustercapacityLifecycleHookDrainHookTopic07C1229F": { - "id": "AllowInvoke:awsecsintegFargateClustercapacityLifecycleHookDrainHookTopic07C1229F", - "path": "aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/AllowInvoke:awsecsintegFargateClustercapacityLifecycleHookDrainHookTopic07C1229F", + "AllowInvoke:awsecsintegFargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHook7BA31FB2": { + "id": "AllowInvoke:awsecsintegFargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHook7BA31FB2", + "path": "aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/AllowInvoke:awsecsintegFargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHook7BA31FB2", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -893,7 +901,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" + "Ref": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" } } }, @@ -902,25 +910,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ/FargateCluster/capacity/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" - }, "endpoint": { "Fn::GetAtt": [ "FargateClustercapacityDrainECSHookFunction3E60E6D0", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" } } }, @@ -944,20 +952,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ/FargateCluster/capacity/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/FargateCluster/capacity/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/FargateCluster/capacity/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/FargateCluster/capacity/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ/FargateCluster/capacity/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1039,7 +1047,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" + "Ref": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" } } ], @@ -1079,11 +1087,11 @@ "autoScalingGroupName": { "Ref": "FargateClustercapacityASGE4034F96" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "FargateClustercapacityLifecycleHookDrainHookTopic390A0E34" + "Ref": "FargateClustercapacityLifecycleHookDrainHookTopicLifecycleHookDrainHookC59604DA" }, "roleArn": { "Fn::GetAtt": [ @@ -1416,7 +1424,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/CapacityProvidersDefaultTestDeployAssert30F9785A.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/CapacityProvidersDefaultTestDeployAssert30F9785A.assets.json index ffd41162dab36..ea59cb7ced7cd 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/CapacityProvidersDefaultTestDeployAssert30F9785A.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/CapacityProvidersDefaultTestDeployAssert30F9785A.assets.json @@ -1,5 +1,5 @@ { - "version": "35.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/cdk.out index c5cb2e5de6344..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"35.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ-default-capacity-provider.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ-default-capacity-provider.assets.json index f5b0f09fcf27a..344c14b85a958 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ-default-capacity-provider.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ-default-capacity-provider.assets.json @@ -1,7 +1,7 @@ { - "version": "35.0.0", + "version": "36.0.0", "files": { - "2f0eb2fad566370d94ec94c0aa2cde3b1f3d651b9c7282628389bc160b9d595f": { + "3641f89a63ac7025c1e3d14b5be18d01a41ac1aa97f1f27087761de25ee94b7c": { "source": { "path": "integ-default-capacity-provider.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "2f0eb2fad566370d94ec94c0aa2cde3b1f3d651b9c7282628389bc160b9d595f.json", + "objectKey": "3641f89a63ac7025c1e3d14b5be18d01a41ac1aa97f1f27087761de25ee94b7c.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ-default-capacity-provider.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ-default-capacity-provider.template.json index e761add82d601..4634118fc511a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ-default-capacity-provider.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ-default-capacity-provider.template.json @@ -820,7 +820,7 @@ "ASGDrainECSHookFunctionServiceRoleC12963BB" ] }, - "ASGDrainECSHookFunctionAllowInvokeintegdefaultcapacityproviderASGLifecycleHookDrainHookTopicB8CF8925702E570F": { + "ASGDrainECSHookFunctionAllowInvokeintegdefaultcapacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook697D0E800A85DAD0": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -832,11 +832,11 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, - "ASGDrainECSHookFunctionTopicD6FC59F7": { + "ASGDrainECSHookFunctionTopicLifecycleHookDrainHook8B240409": { "Type": "AWS::SNS::Subscription", "Properties": { "Endpoint": { @@ -847,11 +847,11 @@ }, "Protocol": "lambda", "TopicArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, - "ASGLifecycleHookDrainHookTopicA8AD4ACB": { + "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -894,7 +894,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } ], @@ -918,7 +918,7 @@ "HeartbeatTimeout": 300, "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ.json index 206b10c058c3f..07d1c0d09b530 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "35.0.0", + "version": "36.0.0", "testCases": { "CapacityProviders/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/manifest.json index 0e18bb71ea264..a240d01494ffe 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "35.0.0", + "version": "36.0.0", "artifacts": { "integ-default-capacity-provider.assets": { "type": "cdk:asset-manifest", @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/2f0eb2fad566370d94ec94c0aa2cde3b1f3d651b9c7282628389bc160b9d595f.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/3641f89a63ac7025c1e3d14b5be18d01a41ac1aa97f1f27087761de25ee94b7c.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -238,22 +238,22 @@ "data": "ASGDrainECSHookFunction5F24CF4D" } ], - "/integ-default-capacity-provider/ASG/DrainECSHook/Function/AllowInvoke:integdefaultcapacityproviderASGLifecycleHookDrainHookTopicB8CF8925": [ + "/integ-default-capacity-provider/ASG/DrainECSHook/Function/AllowInvoke:integdefaultcapacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook697D0E80": [ { "type": "aws:cdk:logicalId", - "data": "ASGDrainECSHookFunctionAllowInvokeintegdefaultcapacityproviderASGLifecycleHookDrainHookTopicB8CF8925702E570F" + "data": "ASGDrainECSHookFunctionAllowInvokeintegdefaultcapacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook697D0E800A85DAD0" } ], - "/integ-default-capacity-provider/ASG/DrainECSHook/Function/Topic/Resource": [ + "/integ-default-capacity-provider/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ASGDrainECSHookFunctionTopicD6FC59F7" + "data": "ASGDrainECSHookFunctionTopicLifecycleHookDrainHook8B240409" } ], - "/integ-default-capacity-provider/ASG/LifecycleHookDrainHook/Topic/Resource": [ + "/integ-default-capacity-provider/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "data": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } ], "/integ-default-capacity-provider/ASG/LifecycleHookDrainHook/Role/Resource": [ @@ -315,6 +315,33 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "ASGDrainECSHookFunctionAllowInvokeintegdefaultcapacityproviderASGLifecycleHookDrainHookTopicB8CF8925702E570F": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGDrainECSHookFunctionAllowInvokeintegdefaultcapacityproviderASGLifecycleHookDrainHookTopicB8CF8925702E570F", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ASGDrainECSHookFunctionTopicD6FC59F7": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGDrainECSHookFunctionTopicD6FC59F7", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ASGLifecycleHookDrainHookTopicA8AD4ACB": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGLifecycleHookDrainHookTopicA8AD4ACB", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "integ-default-capacity-provider" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/tree.json index f253d289f9876..ffbe6c0899316 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.default-capacity-provider.js.snapshot/tree.json @@ -31,8 +31,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", + "version": "0.0.0" } }, "PublicSubnet1": { @@ -75,16 +75,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" } }, "Acl": { "id": "Acl", "path": "integ-default-capacity-provider/Vpc/PublicSubnet1/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -105,8 +105,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" } }, "RouteTableAssociation": { @@ -124,8 +124,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" } }, "DefaultRoute": { @@ -144,8 +144,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" } }, "EIP": { @@ -164,8 +164,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" } }, "NATGateway": { @@ -192,14 +192,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "0.0.0" } }, "PublicSubnet2": { @@ -242,16 +242,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" } }, "Acl": { "id": "Acl", "path": "integ-default-capacity-provider/Vpc/PublicSubnet2/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -272,8 +272,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" } }, "RouteTableAssociation": { @@ -291,8 +291,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" } }, "DefaultRoute": { @@ -311,8 +311,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" } }, "EIP": { @@ -331,8 +331,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" } }, "NATGateway": { @@ -359,14 +359,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "0.0.0" } }, "PrivateSubnet1": { @@ -409,16 +409,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" } }, "Acl": { "id": "Acl", "path": "integ-default-capacity-provider/Vpc/PrivateSubnet1/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -439,8 +439,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" } }, "RouteTableAssociation": { @@ -458,8 +458,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" } }, "DefaultRoute": { @@ -478,14 +478,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "0.0.0" } }, "PrivateSubnet2": { @@ -528,16 +528,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" } }, "Acl": { "id": "Acl", "path": "integ-default-capacity-provider/Vpc/PrivateSubnet2/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -558,8 +558,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" } }, "RouteTableAssociation": { @@ -577,8 +577,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" } }, "DefaultRoute": { @@ -597,14 +597,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "0.0.0" } }, "IGW": { @@ -622,8 +622,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", + "version": "0.0.0" } }, "VPCGW": { @@ -641,14 +641,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.Vpc", + "version": "0.0.0" } }, "TaskDef": { @@ -663,8 +663,8 @@ "id": "ImportTaskRole", "path": "integ-default-capacity-provider/TaskDef/TaskRole/ImportTaskRole", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "Resource": { @@ -688,14 +688,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" } }, "Resource": { @@ -726,22 +726,22 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.CfnTaskDefinition", + "version": "0.0.0" } }, "web": { "id": "web", "path": "integ-default-capacity-provider/TaskDef/web", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.ContainerDefinition", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.Ec2TaskDefinition", + "version": "0.0.0" } }, "ASG": { @@ -778,14 +778,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "0.0.0" } }, "InstanceRole": { @@ -796,8 +796,8 @@ "id": "ImportInstanceRole", "path": "integ-default-capacity-provider/ASG/InstanceRole/ImportInstanceRole", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "Resource": { @@ -827,8 +827,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" } }, "DefaultPolicy": { @@ -897,20 +897,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" } }, "InstanceProfile": { @@ -927,16 +927,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.CfnInstanceProfile", + "version": "0.0.0" } }, "ImportedInstanceProfile": { "id": "ImportedInstanceProfile", "path": "integ-default-capacity-provider/ASG/ImportedInstanceProfile", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "LaunchTemplate": { @@ -1022,14 +1022,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.CfnLaunchTemplate", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ec2.LaunchTemplate", + "version": "0.0.0" } }, "ASG": { @@ -1069,8 +1069,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_autoscaling.CfnAutoScalingGroup", + "version": "0.0.0" } }, "DrainECSHook": { @@ -1089,8 +1089,8 @@ "id": "ImportServiceRole", "path": "integ-default-capacity-provider/ASG/DrainECSHook/Function/ServiceRole/ImportServiceRole", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "Resource": { @@ -1134,8 +1134,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" } }, "DefaultPolicy": { @@ -1233,20 +1233,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" } }, "Resource": { @@ -1283,13 +1283,13 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", + "version": "0.0.0" } }, - "AllowInvoke:integdefaultcapacityproviderASGLifecycleHookDrainHookTopicB8CF8925": { - "id": "AllowInvoke:integdefaultcapacityproviderASGLifecycleHookDrainHookTopicB8CF8925", - "path": "integ-default-capacity-provider/ASG/DrainECSHook/Function/AllowInvoke:integdefaultcapacityproviderASGLifecycleHookDrainHookTopicB8CF8925", + "AllowInvoke:integdefaultcapacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook697D0E80": { + "id": "AllowInvoke:integdefaultcapacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook697D0E80", + "path": "integ-default-capacity-provider/ASG/DrainECSHook/Function/AllowInvoke:integdefaultcapacityproviderASGLifecycleHookDrainHookTopicLifecycleHookDrainHook697D0E80", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1302,22 +1302,22 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_lambda.CfnPermission", + "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "integ-default-capacity-provider/ASG/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "integ-default-capacity-provider/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "integ-default-capacity-provider/ASG/DrainECSHook/Function/Topic/Resource", + "path": "integ-default-capacity-provider/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { @@ -1329,25 +1329,25 @@ }, "protocol": "lambda", "topicArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_sns.CfnSubscription", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_sns.Subscription", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" } } }, @@ -1360,13 +1360,13 @@ "id": "LifecycleHookDrainHook", "path": "integ-default-capacity-provider/ASG/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "integ-default-capacity-provider/ASG/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "integ-default-capacity-provider/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "integ-default-capacity-provider/ASG/LifecycleHookDrainHook/Topic/Resource", + "path": "integ-default-capacity-provider/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1379,14 +1379,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_sns.CfnTopic", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_sns.Topic", + "version": "0.0.0" } }, "Role": { @@ -1397,8 +1397,8 @@ "id": "ImportRole", "path": "integ-default-capacity-provider/ASG/LifecycleHookDrainHook/Role/ImportRole", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "Resource": { @@ -1428,8 +1428,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" } }, "DefaultPolicy": { @@ -1448,7 +1448,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } ], @@ -1463,20 +1463,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" } }, "Resource": { @@ -1492,7 +1492,7 @@ "heartbeatTimeout": 300, "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" }, "roleArn": { "Fn::GetAtt": [ @@ -1503,36 +1503,36 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_autoscaling.CfnLifecycleHook", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_autoscaling.LifecycleHook", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_autoscaling.AutoScalingGroup", + "version": "0.0.0" } }, "SsmParameterValue:--aws--service--ecs--optimized-ami--amazon-linux-2--recommended--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter": { "id": "SsmParameterValue:--aws--service--ecs--optimized-ami--amazon-linux-2--recommended--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter", "path": "integ-default-capacity-provider/SsmParameterValue:--aws--service--ecs--optimized-ami--amazon-linux-2--recommended--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" } }, "SsmParameterValue:--aws--service--ecs--optimized-ami--amazon-linux-2--recommended--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118": { "id": "SsmParameterValue:--aws--service--ecs--optimized-ami--amazon-linux-2--recommended--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118", "path": "integ-default-capacity-provider/SsmParameterValue:--aws--service--ecs--optimized-ami--amazon-linux-2--recommended--image_id:C96584B6-F00A-464E-AD19-53AFF4B05118", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "EC2CapacityProvider": { @@ -1559,14 +1559,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.CfnCapacityProvider", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.AsgCapacityProvider", + "version": "0.0.0" } }, "EC2CPCluster": { @@ -1581,8 +1581,8 @@ "aws:cdk:cloudformation:props": {} }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.CfnCluster", + "version": "0.0.0" } }, "EC2CPCluster": { @@ -1615,14 +1615,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.CfnClusterCapacityProviderAssociations", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.Cluster", + "version": "0.0.0" } }, "EC2Service": { @@ -1656,36 +1656,36 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.CfnService", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_ecs.Ec2Service", + "version": "0.0.0" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "integ-default-capacity-provider/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "integ-default-capacity-provider/CheckBootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" } }, "CapacityProviders": { @@ -1712,22 +1712,22 @@ "id": "BootstrapVersion", "path": "CapacityProviders/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "CapacityProviders/DefaultTest/DeployAssert/CheckBootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" } } }, @@ -1752,8 +1752,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/DeploymentAlarmsDefaultTestDeployAssertAFB973D1.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/DeploymentAlarmsDefaultTestDeployAssertAFB973D1.assets.json index d528cc1b8b11f..d7a0ed3eb9b99 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/DeploymentAlarmsDefaultTestDeployAssertAFB973D1.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/DeploymentAlarmsDefaultTestDeployAssertAFB973D1.assets.json @@ -1,5 +1,5 @@ { - "version": "33.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/__entrypoint__.js b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/__entrypoint__.js deleted file mode 100644 index c83ecebaaadac..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/__entrypoint__.js +++ /dev/null @@ -1,147 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.withRetries = exports.handler = exports.external = void 0; -const https = require("https"); -const url = require("url"); -// for unit tests -exports.external = { - sendHttpRequest: defaultSendHttpRequest, - log: defaultLog, - includeStackTraces: true, - userHandlerIndex: './index', -}; -const CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; -const MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; -async function handler(event, context) { - const sanitizedEvent = { ...event, ResponseURL: '...' }; - exports.external.log(JSON.stringify(sanitizedEvent, undefined, 2)); - // ignore DELETE event when the physical resource ID is the marker that - // indicates that this DELETE is a subsequent DELETE to a failed CREATE - // operation. - if (event.RequestType === 'Delete' && event.PhysicalResourceId === CREATE_FAILED_PHYSICAL_ID_MARKER) { - exports.external.log('ignoring DELETE event caused by a failed CREATE event'); - await submitResponse('SUCCESS', event); - return; - } - try { - // invoke the user handler. this is intentionally inside the try-catch to - // ensure that if there is an error it's reported as a failure to - // cloudformation (otherwise cfn waits). - // eslint-disable-next-line @typescript-eslint/no-require-imports - const userHandler = require(exports.external.userHandlerIndex).handler; - const result = await userHandler(sanitizedEvent, context); - // validate user response and create the combined event - const responseEvent = renderResponse(event, result); - // submit to cfn as success - await submitResponse('SUCCESS', responseEvent); - } - catch (e) { - const resp = { - ...event, - Reason: exports.external.includeStackTraces ? e.stack : e.message, - }; - if (!resp.PhysicalResourceId) { - // special case: if CREATE fails, which usually implies, we usually don't - // have a physical resource id. in this case, the subsequent DELETE - // operation does not have any meaning, and will likely fail as well. to - // address this, we use a marker so the provider framework can simply - // ignore the subsequent DELETE. - if (event.RequestType === 'Create') { - exports.external.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); - resp.PhysicalResourceId = CREATE_FAILED_PHYSICAL_ID_MARKER; - } - else { - // otherwise, if PhysicalResourceId is not specified, something is - // terribly wrong because all other events should have an ID. - exports.external.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(event)}`); - } - } - // this is an actual error, fail the activity altogether and exist. - await submitResponse('FAILED', resp); - } -} -exports.handler = handler; -function renderResponse(cfnRequest, handlerResponse = {}) { - // if physical ID is not returned, we have some defaults for you based - // on the request type. - const physicalResourceId = handlerResponse.PhysicalResourceId ?? cfnRequest.PhysicalResourceId ?? cfnRequest.RequestId; - // if we are in DELETE and physical ID was changed, it's an error. - if (cfnRequest.RequestType === 'Delete' && physicalResourceId !== cfnRequest.PhysicalResourceId) { - throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${handlerResponse.PhysicalResourceId}" during deletion`); - } - // merge request event and result event (result prevails). - return { - ...cfnRequest, - ...handlerResponse, - PhysicalResourceId: physicalResourceId, - }; -} -async function submitResponse(status, event) { - const json = { - Status: status, - Reason: event.Reason ?? status, - StackId: event.StackId, - RequestId: event.RequestId, - PhysicalResourceId: event.PhysicalResourceId || MISSING_PHYSICAL_ID_MARKER, - LogicalResourceId: event.LogicalResourceId, - NoEcho: event.NoEcho, - Data: event.Data, - }; - exports.external.log('submit response to cloudformation', json); - const responseBody = JSON.stringify(json); - const parsedUrl = url.parse(event.ResponseURL); - const req = { - hostname: parsedUrl.hostname, - path: parsedUrl.path, - method: 'PUT', - headers: { - 'content-type': '', - 'content-length': Buffer.byteLength(responseBody, 'utf8'), - }, - }; - const retryOptions = { - attempts: 5, - sleep: 1000, - }; - await withRetries(retryOptions, exports.external.sendHttpRequest)(req, responseBody); -} -async function defaultSendHttpRequest(options, responseBody) { - return new Promise((resolve, reject) => { - try { - const request = https.request(options, _ => resolve()); - request.on('error', reject); - request.write(responseBody); - request.end(); - } - catch (e) { - reject(e); - } - }); -} -function defaultLog(fmt, ...params) { - // eslint-disable-next-line no-console - console.log(fmt, ...params); -} -function withRetries(options, fn) { - return async (...xs) => { - let attempts = options.attempts; - let ms = options.sleep; - while (true) { - try { - return await fn(...xs); - } - catch (e) { - if (attempts-- <= 0) { - throw e; - } - await sleep(Math.floor(Math.random() * ms)); - ms *= 2; - } - } - }; -} -exports.withRetries = withRetries; -async function sleep(ms) { - return new Promise((ok) => setTimeout(ok, ms)); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWpzLWVudHJ5cG9pbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJub2RlanMtZW50cnlwb2ludC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBRTNCLGlCQUFpQjtBQUNKLFFBQUEsUUFBUSxHQUFHO0lBQ3RCLGVBQWUsRUFBRSxzQkFBc0I7SUFDdkMsR0FBRyxFQUFFLFVBQVU7SUFDZixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGdCQUFnQixFQUFFLFNBQVM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sZ0NBQWdDLEdBQUcsd0RBQXdELENBQUM7QUFDbEcsTUFBTSwwQkFBMEIsR0FBRyw4REFBOEQsQ0FBQztBQVczRixLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQWtELEVBQUUsT0FBMEI7SUFDMUcsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDeEQsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFM0QsdUVBQXVFO0lBQ3ZFLHVFQUF1RTtJQUN2RSxhQUFhO0lBQ2IsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssZ0NBQWdDLEVBQUU7UUFDbkcsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUN0RSxNQUFNLGNBQWMsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkMsT0FBTztLQUNSO0lBRUQsSUFBSTtRQUNGLHlFQUF5RTtRQUN6RSxpRUFBaUU7UUFDakUsd0NBQXdDO1FBQ3hDLGlFQUFpRTtRQUNqRSxNQUFNLFdBQVcsR0FBWSxPQUFPLENBQUMsZ0JBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxNQUFNLE1BQU0sR0FBRyxNQUFNLFdBQVcsQ0FBQyxjQUFjLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFMUQsdURBQXVEO1FBQ3ZELE1BQU0sYUFBYSxHQUFHLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFcEQsMkJBQTJCO1FBQzNCLE1BQU0sY0FBYyxDQUFDLFNBQVMsRUFBRSxhQUFhLENBQUMsQ0FBQztLQUNoRDtJQUFDLE9BQU8sQ0FBTSxFQUFFO1FBQ2YsTUFBTSxJQUFJLEdBQWE7WUFDckIsR0FBRyxLQUFLO1lBQ1IsTUFBTSxFQUFFLGdCQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPO1NBQzFELENBQUM7UUFFRixJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFO1lBQzVCLHlFQUF5RTtZQUN6RSxtRUFBbUU7WUFDbkUsd0VBQXdFO1lBQ3hFLHFFQUFxRTtZQUNyRSxnQ0FBZ0M7WUFDaEMsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtnQkFDbEMsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsNEdBQTRHLENBQUMsQ0FBQztnQkFDM0gsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGdDQUFnQyxDQUFDO2FBQzVEO2lCQUFNO2dCQUNMLGtFQUFrRTtnQkFDbEUsNkRBQTZEO2dCQUM3RCxnQkFBUSxDQUFDLEdBQUcsQ0FBQyw2REFBNkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDcEc7U0FDRjtRQUVELG1FQUFtRTtRQUNuRSxNQUFNLGNBQWMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7S0FDdEM7QUFDSCxDQUFDO0FBbkRELDBCQW1EQztBQUVELFNBQVMsY0FBYyxDQUNyQixVQUF5RixFQUN6RixrQkFBMEMsRUFBRztJQUU3QyxzRUFBc0U7SUFDdEUsdUJBQXVCO0lBQ3ZCLE1BQU0sa0JBQWtCLEdBQUcsZUFBZSxDQUFDLGtCQUFrQixJQUFJLFVBQVUsQ0FBQyxrQkFBa0IsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDO0lBRXZILGtFQUFrRTtJQUNsRSxJQUFJLFVBQVUsQ0FBQyxXQUFXLEtBQUssUUFBUSxJQUFJLGtCQUFrQixLQUFLLFVBQVUsQ0FBQyxrQkFBa0IsRUFBRTtRQUMvRixNQUFNLElBQUksS0FBSyxDQUFDLHdEQUF3RCxVQUFVLENBQUMsa0JBQWtCLFNBQVMsZUFBZSxDQUFDLGtCQUFrQixtQkFBbUIsQ0FBQyxDQUFDO0tBQ3RLO0lBRUQsMERBQTBEO0lBQzFELE9BQU87UUFDTCxHQUFHLFVBQVU7UUFDYixHQUFHLGVBQWU7UUFDbEIsa0JBQWtCLEVBQUUsa0JBQWtCO0tBQ3ZDLENBQUM7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLGNBQWMsQ0FBQyxNQUE0QixFQUFFLEtBQWU7SUFDekUsTUFBTSxJQUFJLEdBQW1EO1FBQzNELE1BQU0sRUFBRSxNQUFNO1FBQ2QsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLElBQUksTUFBTTtRQUM5QixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87UUFDdEIsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1FBQzFCLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSwwQkFBMEI7UUFDMUUsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtRQUMxQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO0tBQ2pCLENBQUM7SUFFRixnQkFBUSxDQUFDLEdBQUcsQ0FBQyxtQ0FBbUMsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUV4RCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFDLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQy9DLE1BQU0sR0FBRyxHQUFHO1FBQ1YsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO1FBQzVCLElBQUksRUFBRSxTQUFTLENBQUMsSUFBSTtRQUNwQixNQUFNLEVBQUUsS0FBSztRQUNiLE9BQU8sRUFBRTtZQUNQLGNBQWMsRUFBRSxFQUFFO1lBQ2xCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQztTQUMxRDtLQUNGLENBQUM7SUFFRixNQUFNLFlBQVksR0FBRztRQUNuQixRQUFRLEVBQUUsQ0FBQztRQUNYLEtBQUssRUFBRSxJQUFJO0tBQ1osQ0FBQztJQUNGLE1BQU0sV0FBVyxDQUFDLFlBQVksRUFBRSxnQkFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsQ0FBQztBQUMvRSxDQUFDO0FBRUQsS0FBSyxVQUFVLHNCQUFzQixDQUFDLE9BQTZCLEVBQUUsWUFBb0I7SUFDdkYsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNyQyxJQUFJO1lBQ0YsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDNUIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1NBQ2Y7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNYO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsR0FBVyxFQUFFLEdBQUcsTUFBYTtJQUMvQyxzQ0FBc0M7SUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQztBQUM5QixDQUFDO0FBU0QsU0FBZ0IsV0FBVyxDQUEwQixPQUFxQixFQUFFLEVBQTRCO0lBQ3RHLE9BQU8sS0FBSyxFQUFFLEdBQUcsRUFBSyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLE9BQU8sSUFBSSxFQUFFO1lBQ1gsSUFBSTtnQkFDRixPQUFPLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDeEI7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRTtvQkFDbkIsTUFBTSxDQUFDLENBQUM7aUJBQ1Q7Z0JBQ0QsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDNUMsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNUO1NBQ0Y7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDO0FBaEJELGtDQWdCQztBQUVELEtBQUssVUFBVSxLQUFLLENBQUMsRUFBVTtJQUM3QixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDakQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG4vLyBmb3IgdW5pdCB0ZXN0c1xuZXhwb3J0IGNvbnN0IGV4dGVybmFsID0ge1xuICBzZW5kSHR0cFJlcXVlc3Q6IGRlZmF1bHRTZW5kSHR0cFJlcXVlc3QsXG4gIGxvZzogZGVmYXVsdExvZyxcbiAgaW5jbHVkZVN0YWNrVHJhY2VzOiB0cnVlLFxuICB1c2VySGFuZGxlckluZGV4OiAnLi9pbmRleCcsXG59O1xuXG5jb25zdCBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUiA9ICdBV1NDREs6OkN1c3RvbVJlc291cmNlUHJvdmlkZXJGcmFtZXdvcms6OkNSRUFURV9GQUlMRUQnO1xuY29uc3QgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpNSVNTSU5HX1BIWVNJQ0FMX0lEJztcblxuZXhwb3J0IHR5cGUgUmVzcG9uc2UgPSBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgSGFuZGxlclJlc3BvbnNlO1xuZXhwb3J0IHR5cGUgSGFuZGxlciA9IChldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCwgY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpID0+IFByb21pc2U8SGFuZGxlclJlc3BvbnNlIHwgdm9pZD47XG5leHBvcnQgdHlwZSBIYW5kbGVyUmVzcG9uc2UgPSB1bmRlZmluZWQgfCB7XG4gIERhdGE/OiBhbnk7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgUmVhc29uPzogc3RyaW5nO1xuICBOb0VjaG8/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIGNvbnRleHQ6IEFXU0xhbWJkYS5Db250ZXh0KSB7XG4gIGNvbnN0IHNhbml0aXplZEV2ZW50ID0geyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH07XG4gIGV4dGVybmFsLmxvZyhKU09OLnN0cmluZ2lmeShzYW5pdGl6ZWRFdmVudCwgdW5kZWZpbmVkLCAyKSk7XG5cbiAgLy8gaWdub3JlIERFTEVURSBldmVudCB3aGVuIHRoZSBwaHlzaWNhbCByZXNvdXJjZSBJRCBpcyB0aGUgbWFya2VyIHRoYXRcbiAgLy8gaW5kaWNhdGVzIHRoYXQgdGhpcyBERUxFVEUgaXMgYSBzdWJzZXF1ZW50IERFTEVURSB0byBhIGZhaWxlZCBDUkVBVEVcbiAgLy8gb3BlcmF0aW9uLlxuICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9PT0gQ1JFQVRFX0ZBSUxFRF9QSFlTSUNBTF9JRF9NQVJLRVIpIHtcbiAgICBleHRlcm5hbC5sb2coJ2lnbm9yaW5nIERFTEVURSBldmVudCBjYXVzZWQgYnkgYSBmYWlsZWQgQ1JFQVRFIGV2ZW50Jyk7XG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBpbnZva2UgdGhlIHVzZXIgaGFuZGxlci4gdGhpcyBpcyBpbnRlbnRpb25hbGx5IGluc2lkZSB0aGUgdHJ5LWNhdGNoIHRvXG4gICAgLy8gZW5zdXJlIHRoYXQgaWYgdGhlcmUgaXMgYW4gZXJyb3IgaXQncyByZXBvcnRlZCBhcyBhIGZhaWx1cmUgdG9cbiAgICAvLyBjbG91ZGZvcm1hdGlvbiAob3RoZXJ3aXNlIGNmbiB3YWl0cykuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCB1c2VySGFuZGxlcjogSGFuZGxlciA9IHJlcXVpcmUoZXh0ZXJuYWwudXNlckhhbmRsZXJJbmRleCkuaGFuZGxlcjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB1c2VySGFuZGxlcihzYW5pdGl6ZWRFdmVudCwgY29udGV4dCk7XG5cbiAgICAvLyB2YWxpZGF0ZSB1c2VyIHJlc3BvbnNlIGFuZCBjcmVhdGUgdGhlIGNvbWJpbmVkIGV2ZW50XG4gICAgY29uc3QgcmVzcG9uc2VFdmVudCA9IHJlbmRlclJlc3BvbnNlKGV2ZW50LCByZXN1bHQpO1xuXG4gICAgLy8gc3VibWl0IHRvIGNmbiBhcyBzdWNjZXNzXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCByZXNwb25zZUV2ZW50KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgY29uc3QgcmVzcDogUmVzcG9uc2UgPSB7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIFJlYXNvbjogZXh0ZXJuYWwuaW5jbHVkZVN0YWNrVHJhY2VzID8gZS5zdGFjayA6IGUubWVzc2FnZSxcbiAgICB9O1xuXG4gICAgaWYgKCFyZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCkge1xuICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgLy8gaGF2ZSBhIHBoeXNpY2FsIHJlc291cmNlIGlkLiBpbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXF1ZW50IERFTEVURVxuICAgICAgLy8gb3BlcmF0aW9uIGRvZXMgbm90IGhhdmUgYW55IG1lYW5pbmcsIGFuZCB3aWxsIGxpa2VseSBmYWlsIGFzIHdlbGwuIHRvXG4gICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgIC8vIGlnbm9yZSB0aGUgc3Vic2VxdWVudCBERUxFVEUuXG4gICAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnKSB7XG4gICAgICAgIGV4dGVybmFsLmxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICByZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gb3RoZXJ3aXNlLCBpZiBQaHlzaWNhbFJlc291cmNlSWQgaXMgbm90IHNwZWNpZmllZCwgc29tZXRoaW5nIGlzXG4gICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgZXh0ZXJuYWwubG9nKGBFUlJPUjogTWFsZm9ybWVkIGV2ZW50LiBcIlBoeXNpY2FsUmVzb3VyY2VJZFwiIGlzIHJlcXVpcmVkOiAke0pTT04uc3RyaW5naWZ5KGV2ZW50KX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyB0aGlzIGlzIGFuIGFjdHVhbCBlcnJvciwgZmFpbCB0aGUgYWN0aXZpdHkgYWx0b2dldGhlciBhbmQgZXhpc3QuXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ0ZBSUxFRCcsIHJlc3ApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlbmRlclJlc3BvbnNlKFxuICBjZm5SZXF1ZXN0OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgeyBQaHlzaWNhbFJlc291cmNlSWQ/OiBzdHJpbmcgfSxcbiAgaGFuZGxlclJlc3BvbnNlOiB2b2lkIHwgSGFuZGxlclJlc3BvbnNlID0geyB9KTogUmVzcG9uc2Uge1xuXG4gIC8vIGlmIHBoeXNpY2FsIElEIGlzIG5vdCByZXR1cm5lZCwgd2UgaGF2ZSBzb21lIGRlZmF1bHRzIGZvciB5b3UgYmFzZWRcbiAgLy8gb24gdGhlIHJlcXVlc3QgdHlwZS5cbiAgY29uc3QgcGh5c2ljYWxSZXNvdXJjZUlkID0gaGFuZGxlclJlc3BvbnNlLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlJlcXVlc3RJZDtcblxuICAvLyBpZiB3ZSBhcmUgaW4gREVMRVRFIGFuZCBwaHlzaWNhbCBJRCB3YXMgY2hhbmdlZCwgaXQncyBhbiBlcnJvci5cbiAgaWYgKGNmblJlcXVlc3QuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIHBoeXNpY2FsUmVzb3VyY2VJZCAhPT0gY2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERFTEVURTogY2Fubm90IGNoYW5nZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSBcIiR7Y2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWR9XCIgdG8gXCIke2hhbmRsZXJSZXNwb25zZS5QaHlzaWNhbFJlc291cmNlSWR9XCIgZHVyaW5nIGRlbGV0aW9uYCk7XG4gIH1cblxuICAvLyBtZXJnZSByZXF1ZXN0IGV2ZW50IGFuZCByZXN1bHQgZXZlbnQgKHJlc3VsdCBwcmV2YWlscykuXG4gIHJldHVybiB7XG4gICAgLi4uY2ZuUmVxdWVzdCxcbiAgICAuLi5oYW5kbGVyUmVzcG9uc2UsXG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN1Ym1pdFJlc3BvbnNlKHN0YXR1czogJ1NVQ0NFU1MnIHwgJ0ZBSUxFRCcsIGV2ZW50OiBSZXNwb25zZSkge1xuICBjb25zdCBqc29uOiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlID0ge1xuICAgIFN0YXR1czogc3RhdHVzLFxuICAgIFJlYXNvbjogZXZlbnQuUmVhc29uID8/IHN0YXR1cyxcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkIHx8IE1JU1NJTkdfUEhZU0lDQUxfSURfTUFSS0VSLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBOb0VjaG86IGV2ZW50Lk5vRWNobyxcbiAgICBEYXRhOiBldmVudC5EYXRhLFxuICB9O1xuXG4gIGV4dGVybmFsLmxvZygnc3VibWl0IHJlc3BvbnNlIHRvIGNsb3VkZm9ybWF0aW9uJywganNvbik7XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoanNvbik7XG4gIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShldmVudC5SZXNwb25zZVVSTCk7XG4gIGNvbnN0IHJlcSA9IHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogQnVmZmVyLmJ5dGVMZW5ndGgocmVzcG9uc2VCb2R5LCAndXRmOCcpLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3QgcmV0cnlPcHRpb25zID0ge1xuICAgIGF0dGVtcHRzOiA1LFxuICAgIHNsZWVwOiAxMDAwLFxuICB9O1xuICBhd2FpdCB3aXRoUmV0cmllcyhyZXRyeU9wdGlvbnMsIGV4dGVybmFsLnNlbmRIdHRwUmVxdWVzdCkocmVxLCByZXNwb25zZUJvZHkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0U2VuZEh0dHBSZXF1ZXN0KG9wdGlvbnM6IGh0dHBzLlJlcXVlc3RPcHRpb25zLCByZXNwb25zZUJvZHk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCBfID0+IHJlc29sdmUoKSk7XG4gICAgICByZXF1ZXN0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICByZXF1ZXN0LndyaXRlKHJlc3BvbnNlQm9keSk7XG4gICAgICByZXF1ZXN0LmVuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWZhdWx0TG9nKGZtdDogc3RyaW5nLCAuLi5wYXJhbXM6IGFueVtdKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gIGNvbnNvbGUubG9nKGZtdCwgLi4ucGFyYW1zKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXRyeU9wdGlvbnMge1xuICAvKiogSG93IG1hbnkgcmV0cmllcyAod2lsbCBhdCBsZWFzdCB0cnkgb25jZSkgKi9cbiAgcmVhZG9ubHkgYXR0ZW1wdHM6IG51bWJlcjtcbiAgLyoqIFNsZWVwIGJhc2UsIGluIG1zICovXG4gIHJlYWRvbmx5IHNsZWVwOiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB3aXRoUmV0cmllczxBIGV4dGVuZHMgQXJyYXk8YW55PiwgQj4ob3B0aW9uczogUmV0cnlPcHRpb25zLCBmbjogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+KTogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+IHtcbiAgcmV0dXJuIGFzeW5jICguLi54czogQSkgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IG9wdGlvbnMuYXR0ZW1wdHM7XG4gICAgbGV0IG1zID0gb3B0aW9ucy5zbGVlcDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGZuKC4uLnhzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGF0dGVtcHRzLS0gPD0gMCkge1xuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgc2xlZXAoTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbXMpKTtcbiAgICAgICAgbXMgKj0gMjtcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChvaykgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/index.js deleted file mode 100644 index 8cbc0ea437b76..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/index.js +++ /dev/null @@ -1,81 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.handler = void 0; -/* eslint-disable-next-line import/no-extraneous-dependencies */ -const sdk = require("@aws-sdk/client-ec2"); -const ec2 = new sdk.EC2({}); -/** - * The default security group ingress rule. This can be used to both revoke and authorize the rules - */ -function ingressRuleParams(groupId, account) { - return { - GroupId: groupId, - IpPermissions: [{ - UserIdGroupPairs: [{ - GroupId: groupId, - UserId: account, - }], - IpProtocol: '-1', - }], - }; -} -/** - * The default security group egress rule. This can be used to both revoke and authorize the rules - */ -function egressRuleParams(groupId) { - return { - GroupId: groupId, - IpPermissions: [{ - IpRanges: [{ - CidrIp: '0.0.0.0/0', - }], - IpProtocol: '-1', - }], - }; -} -/** - * Process a custom resource request to restrict the default security group - * ingress & egress rules. - * - * When someone turns off the property then this custom resource will be deleted in which - * case we should add back the rules that were removed. - */ -async function handler(event) { - const securityGroupId = event.ResourceProperties.DefaultSecurityGroupId; - const account = event.ResourceProperties.Account; - switch (event.RequestType) { - case 'Create': - return revokeRules(securityGroupId, account); - case 'Update': - return onUpdate(event); - case 'Delete': - return authorizeRules(securityGroupId, account); - } -} -exports.handler = handler; -async function onUpdate(event) { - const oldSg = event.OldResourceProperties.DefaultSecurityGroupId; - const newSg = event.ResourceProperties.DefaultSecurityGroupId; - if (oldSg !== newSg) { - await authorizeRules(oldSg, event.ResourceProperties.Account); - await revokeRules(newSg, event.ResourceProperties.Account); - } - return; -} -/** - * Revoke both ingress and egress rules - */ -async function revokeRules(groupId, account) { - await ec2.revokeSecurityGroupEgress(egressRuleParams(groupId)); - await ec2.revokeSecurityGroupIngress(ingressRuleParams(groupId, account)); - return; -} -/** - * Authorize both ingress and egress rules - */ -async function authorizeRules(groupId, account) { - await ec2.authorizeSecurityGroupIngress(ingressRuleParams(groupId, account)); - await ec2.authorizeSecurityGroupEgress(egressRuleParams(groupId)); - return; -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxnRUFBZ0U7QUFDaEUsMkNBQTJDO0FBRTNDLE1BQU0sR0FBRyxHQUFHLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUU1Qjs7R0FFRztBQUNILFNBQVMsaUJBQWlCLENBQUMsT0FBZSxFQUFFLE9BQWU7SUFHekQsT0FBTztRQUNMLE9BQU8sRUFBRSxPQUFPO1FBQ2hCLGFBQWEsRUFBRSxDQUFDO2dCQUNkLGdCQUFnQixFQUFFLENBQUM7d0JBQ2pCLE9BQU8sRUFBRSxPQUFPO3dCQUNoQixNQUFNLEVBQUUsT0FBTztxQkFDaEIsQ0FBQztnQkFDRixVQUFVLEVBQUUsSUFBSTthQUNqQixDQUFDO0tBQ0gsQ0FBQztBQUNKLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsT0FBZTtJQUN2QyxPQUFPO1FBQ0wsT0FBTyxFQUFFLE9BQU87UUFDaEIsYUFBYSxFQUFFLENBQUM7Z0JBQ2QsUUFBUSxFQUFFLENBQUM7d0JBQ1QsTUFBTSxFQUFFLFdBQVc7cUJBQ3BCLENBQUM7Z0JBQ0YsVUFBVSxFQUFFLElBQUk7YUFDakIsQ0FBQztLQUNILENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0ksS0FBSyxVQUFVLE9BQU8sQ0FBQyxLQUFrRDtJQUM5RSxNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUMsa0JBQWtCLENBQUMsc0JBQXNCLENBQUM7SUFDeEUsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQztJQUNqRCxRQUFRLEtBQUssQ0FBQyxXQUFXLEVBQUU7UUFDekIsS0FBSyxRQUFRO1lBQ1gsT0FBTyxXQUFXLENBQUMsZUFBZSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQy9DLEtBQUssUUFBUTtZQUNYLE9BQU8sUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3pCLEtBQUssUUFBUTtZQUNYLE9BQU8sY0FBYyxDQUFDLGVBQWUsRUFBRSxPQUFPLENBQUMsQ0FBQztLQUNuRDtBQUNILENBQUM7QUFYRCwwQkFXQztBQUNELEtBQUssVUFBVSxRQUFRLENBQUMsS0FBd0Q7SUFDOUUsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLHFCQUFxQixDQUFDLHNCQUFzQixDQUFDO0lBQ2pFLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxzQkFBc0IsQ0FBQztJQUM5RCxJQUFJLEtBQUssS0FBSyxLQUFLLEVBQUU7UUFDbkIsTUFBTSxjQUFjLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5RCxNQUFNLFdBQVcsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0tBQzVEO0lBQ0QsT0FBTztBQUNULENBQUM7QUFFRDs7R0FFRztBQUNILEtBQUssVUFBVSxXQUFXLENBQUMsT0FBZSxFQUFFLE9BQWU7SUFDekQsTUFBTSxHQUFHLENBQUMseUJBQXlCLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUMvRCxNQUFNLEdBQUcsQ0FBQywwQkFBMEIsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUMxRSxPQUFPO0FBQ1QsQ0FBQztBQUVEOztHQUVHO0FBQ0gsS0FBSyxVQUFVLGNBQWMsQ0FBQyxPQUFlLEVBQUUsT0FBZTtJQUM1RCxNQUFNLEdBQUcsQ0FBQyw2QkFBNkIsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUM3RSxNQUFNLEdBQUcsQ0FBQyw0QkFBNEIsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ2xFLE9BQU87QUFDVCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuaW1wb3J0ICogYXMgc2RrIGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1lYzInO1xuXG5jb25zdCBlYzIgPSBuZXcgc2RrLkVDMih7fSk7XG5cbi8qKlxuICogVGhlIGRlZmF1bHQgc2VjdXJpdHkgZ3JvdXAgaW5ncmVzcyBydWxlLiBUaGlzIGNhbiBiZSB1c2VkIHRvIGJvdGggcmV2b2tlIGFuZCBhdXRob3JpemUgdGhlIHJ1bGVzXG4gKi9cbmZ1bmN0aW9uIGluZ3Jlc3NSdWxlUGFyYW1zKGdyb3VwSWQ6IHN0cmluZywgYWNjb3VudDogc3RyaW5nKTpcbnNkay5SZXZva2VTZWN1cml0eUdyb3VwSW5ncmVzc0NvbW1hbmRJbnB1dFxufCBzZGsuQXV0aG9yaXplU2VjdXJpdHlHcm91cEluZ3Jlc3NDb21tYW5kSW5wdXQge1xuICByZXR1cm4ge1xuICAgIEdyb3VwSWQ6IGdyb3VwSWQsXG4gICAgSXBQZXJtaXNzaW9uczogW3tcbiAgICAgIFVzZXJJZEdyb3VwUGFpcnM6IFt7XG4gICAgICAgIEdyb3VwSWQ6IGdyb3VwSWQsXG4gICAgICAgIFVzZXJJZDogYWNjb3VudCxcbiAgICAgIH1dLFxuICAgICAgSXBQcm90b2NvbDogJy0xJyxcbiAgICB9XSxcbiAgfTtcbn1cblxuLyoqXG4gKiBUaGUgZGVmYXVsdCBzZWN1cml0eSBncm91cCBlZ3Jlc3MgcnVsZS4gVGhpcyBjYW4gYmUgdXNlZCB0byBib3RoIHJldm9rZSBhbmQgYXV0aG9yaXplIHRoZSBydWxlc1xuICovXG5mdW5jdGlvbiBlZ3Jlc3NSdWxlUGFyYW1zKGdyb3VwSWQ6IHN0cmluZyk6IHNkay5SZXZva2VTZWN1cml0eUdyb3VwRWdyZXNzQ29tbWFuZElucHV0IHwgc2RrLkF1dGhvcml6ZVNlY3VyaXR5R3JvdXBFZ3Jlc3NDb21tYW5kSW5wdXQge1xuICByZXR1cm4ge1xuICAgIEdyb3VwSWQ6IGdyb3VwSWQsXG4gICAgSXBQZXJtaXNzaW9uczogW3tcbiAgICAgIElwUmFuZ2VzOiBbe1xuICAgICAgICBDaWRySXA6ICcwLjAuMC4wLzAnLFxuICAgICAgfV0sXG4gICAgICBJcFByb3RvY29sOiAnLTEnLFxuICAgIH1dLFxuICB9O1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSBjdXN0b20gcmVzb3VyY2UgcmVxdWVzdCB0byByZXN0cmljdCB0aGUgZGVmYXVsdCBzZWN1cml0eSBncm91cFxuICogaW5ncmVzcyAmIGVncmVzcyBydWxlcy5cbiAqXG4gKiBXaGVuIHNvbWVvbmUgdHVybnMgb2ZmIHRoZSBwcm9wZXJ0eSB0aGVuIHRoaXMgY3VzdG9tIHJlc291cmNlIHdpbGwgYmUgZGVsZXRlZCBpbiB3aGljaFxuICogY2FzZSB3ZSBzaG91bGQgYWRkIGJhY2sgdGhlIHJ1bGVzIHRoYXQgd2VyZSByZW1vdmVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlcihldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBzZWN1cml0eUdyb3VwSWQgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuRGVmYXVsdFNlY3VyaXR5R3JvdXBJZDtcbiAgY29uc3QgYWNjb3VudCA9IGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5BY2NvdW50O1xuICBzd2l0Y2ggKGV2ZW50LlJlcXVlc3RUeXBlKSB7XG4gICAgY2FzZSAnQ3JlYXRlJzpcbiAgICAgIHJldHVybiByZXZva2VSdWxlcyhzZWN1cml0eUdyb3VwSWQsIGFjY291bnQpO1xuICAgIGNhc2UgJ1VwZGF0ZSc6XG4gICAgICByZXR1cm4gb25VcGRhdGUoZXZlbnQpO1xuICAgIGNhc2UgJ0RlbGV0ZSc6XG4gICAgICByZXR1cm4gYXV0aG9yaXplUnVsZXMoc2VjdXJpdHlHcm91cElkLCBhY2NvdW50KTtcbiAgfVxufVxuYXN5bmMgZnVuY3Rpb24gb25VcGRhdGUoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlVXBkYXRlRXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3Qgb2xkU2cgPSBldmVudC5PbGRSZXNvdXJjZVByb3BlcnRpZXMuRGVmYXVsdFNlY3VyaXR5R3JvdXBJZDtcbiAgY29uc3QgbmV3U2cgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuRGVmYXVsdFNlY3VyaXR5R3JvdXBJZDtcbiAgaWYgKG9sZFNnICE9PSBuZXdTZykge1xuICAgIGF3YWl0IGF1dGhvcml6ZVJ1bGVzKG9sZFNnLCBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuQWNjb3VudCk7XG4gICAgYXdhaXQgcmV2b2tlUnVsZXMobmV3U2csIGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5BY2NvdW50KTtcbiAgfVxuICByZXR1cm47XG59XG5cbi8qKlxuICogUmV2b2tlIGJvdGggaW5ncmVzcyBhbmQgZWdyZXNzIHJ1bGVzXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJldm9rZVJ1bGVzKGdyb3VwSWQ6IHN0cmluZywgYWNjb3VudDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IGVjMi5yZXZva2VTZWN1cml0eUdyb3VwRWdyZXNzKGVncmVzc1J1bGVQYXJhbXMoZ3JvdXBJZCkpO1xuICBhd2FpdCBlYzIucmV2b2tlU2VjdXJpdHlHcm91cEluZ3Jlc3MoaW5ncmVzc1J1bGVQYXJhbXMoZ3JvdXBJZCwgYWNjb3VudCkpO1xuICByZXR1cm47XG59XG5cbi8qKlxuICogQXV0aG9yaXplIGJvdGggaW5ncmVzcyBhbmQgZWdyZXNzIHJ1bGVzXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGF1dGhvcml6ZVJ1bGVzKGdyb3VwSWQ6IHN0cmluZywgYWNjb3VudDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IGVjMi5hdXRob3JpemVTZWN1cml0eUdyb3VwSW5ncmVzcyhpbmdyZXNzUnVsZVBhcmFtcyhncm91cElkLCBhY2NvdW50KSk7XG4gIGF3YWl0IGVjMi5hdXRob3JpemVTZWN1cml0eUdyb3VwRWdyZXNzKGVncmVzc1J1bGVQYXJhbXMoZ3JvdXBJZCkpO1xuICByZXR1cm47XG59XG4iXX0= \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/__entrypoint__.js b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/__entrypoint__.js new file mode 100644 index 0000000000000..1e64dba70bdc0 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/__entrypoint__.js @@ -0,0 +1,147 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.withRetries = exports.handler = exports.external = void 0; +const https = require("https"); +const url = require("url"); +// for unit tests +exports.external = { + sendHttpRequest: defaultSendHttpRequest, + log: defaultLog, + includeStackTraces: true, + userHandlerIndex: './index', +}; +const CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; +const MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; +async function handler(event, context) { + const sanitizedEvent = { ...event, ResponseURL: '...' }; + exports.external.log(JSON.stringify(sanitizedEvent, undefined, 2)); + // ignore DELETE event when the physical resource ID is the marker that + // indicates that this DELETE is a subsequent DELETE to a failed CREATE + // operation. + if (event.RequestType === 'Delete' && event.PhysicalResourceId === CREATE_FAILED_PHYSICAL_ID_MARKER) { + exports.external.log('ignoring DELETE event caused by a failed CREATE event'); + await submitResponse('SUCCESS', event); + return; + } + try { + // invoke the user handler. this is intentionally inside the try-catch to + // ensure that if there is an error it's reported as a failure to + // cloudformation (otherwise cfn waits). + // eslint-disable-next-line @typescript-eslint/no-require-imports + const userHandler = require(exports.external.userHandlerIndex).handler; + const result = await userHandler(sanitizedEvent, context); + // validate user response and create the combined event + const responseEvent = renderResponse(event, result); + // submit to cfn as success + await submitResponse('SUCCESS', responseEvent); + } + catch (e) { + const resp = { + ...event, + Reason: exports.external.includeStackTraces ? e.stack : e.message, + }; + if (!resp.PhysicalResourceId) { + // special case: if CREATE fails, which usually implies, we usually don't + // have a physical resource id. in this case, the subsequent DELETE + // operation does not have any meaning, and will likely fail as well. to + // address this, we use a marker so the provider framework can simply + // ignore the subsequent DELETE. + if (event.RequestType === 'Create') { + exports.external.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); + resp.PhysicalResourceId = CREATE_FAILED_PHYSICAL_ID_MARKER; + } + else { + // otherwise, if PhysicalResourceId is not specified, something is + // terribly wrong because all other events should have an ID. + exports.external.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(event)}`); + } + } + // this is an actual error, fail the activity altogether and exist. + await submitResponse('FAILED', resp); + } +} +exports.handler = handler; +function renderResponse(cfnRequest, handlerResponse = {}) { + // if physical ID is not returned, we have some defaults for you based + // on the request type. + const physicalResourceId = handlerResponse.PhysicalResourceId ?? cfnRequest.PhysicalResourceId ?? cfnRequest.RequestId; + // if we are in DELETE and physical ID was changed, it's an error. + if (cfnRequest.RequestType === 'Delete' && physicalResourceId !== cfnRequest.PhysicalResourceId) { + throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${handlerResponse.PhysicalResourceId}" during deletion`); + } + // merge request event and result event (result prevails). + return { + ...cfnRequest, + ...handlerResponse, + PhysicalResourceId: physicalResourceId, + }; +} +async function submitResponse(status, event) { + const json = { + Status: status, + Reason: event.Reason ?? status, + StackId: event.StackId, + RequestId: event.RequestId, + PhysicalResourceId: event.PhysicalResourceId || MISSING_PHYSICAL_ID_MARKER, + LogicalResourceId: event.LogicalResourceId, + NoEcho: event.NoEcho, + Data: event.Data, + }; + exports.external.log('submit response to cloudformation', json); + const responseBody = JSON.stringify(json); + const parsedUrl = url.parse(event.ResponseURL); + const req = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: 'PUT', + headers: { + 'content-type': '', + 'content-length': Buffer.byteLength(responseBody, 'utf8'), + }, + }; + const retryOptions = { + attempts: 5, + sleep: 1000, + }; + await withRetries(retryOptions, exports.external.sendHttpRequest)(req, responseBody); +} +async function defaultSendHttpRequest(options, responseBody) { + return new Promise((resolve, reject) => { + try { + const request = https.request(options, _ => resolve()); + request.on('error', reject); + request.write(responseBody); + request.end(); + } + catch (e) { + reject(e); + } + }); +} +function defaultLog(fmt, ...params) { + // eslint-disable-next-line no-console + console.log(fmt, ...params); +} +function withRetries(options, fn) { + return async (...xs) => { + let attempts = options.attempts; + let ms = options.sleep; + while (true) { + try { + return await fn(...xs); + } + catch (e) { + if (attempts-- <= 0) { + throw e; + } + await sleep(Math.floor(Math.random() * ms)); + ms *= 2; + } + } + }; +} +exports.withRetries = withRetries; +async function sleep(ms) { + return new Promise((ok) => setTimeout(ok, ms)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBRTNCLGlCQUFpQjtBQUNKLFFBQUEsUUFBUSxHQUFHO0lBQ3RCLGVBQWUsRUFBRSxzQkFBc0I7SUFDdkMsR0FBRyxFQUFFLFVBQVU7SUFDZixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGdCQUFnQixFQUFFLFNBQVM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sZ0NBQWdDLEdBQUcsd0RBQXdELENBQUM7QUFDbEcsTUFBTSwwQkFBMEIsR0FBRyw4REFBOEQsQ0FBQztBQVczRixLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQWtELEVBQUUsT0FBMEI7SUFDMUcsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDeEQsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFM0QsdUVBQXVFO0lBQ3ZFLHVFQUF1RTtJQUN2RSxhQUFhO0lBQ2IsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssZ0NBQWdDLEVBQUU7UUFDbkcsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUN0RSxNQUFNLGNBQWMsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkMsT0FBTztLQUNSO0lBRUQsSUFBSTtRQUNGLHlFQUF5RTtRQUN6RSxpRUFBaUU7UUFDakUsd0NBQXdDO1FBQ3hDLGlFQUFpRTtRQUNqRSxNQUFNLFdBQVcsR0FBWSxPQUFPLENBQUMsZ0JBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxNQUFNLE1BQU0sR0FBRyxNQUFNLFdBQVcsQ0FBQyxjQUFjLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFMUQsdURBQXVEO1FBQ3ZELE1BQU0sYUFBYSxHQUFHLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFcEQsMkJBQTJCO1FBQzNCLE1BQU0sY0FBYyxDQUFDLFNBQVMsRUFBRSxhQUFhLENBQUMsQ0FBQztLQUNoRDtJQUFDLE9BQU8sQ0FBTSxFQUFFO1FBQ2YsTUFBTSxJQUFJLEdBQWE7WUFDckIsR0FBRyxLQUFLO1lBQ1IsTUFBTSxFQUFFLGdCQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPO1NBQzFELENBQUM7UUFFRixJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFO1lBQzVCLHlFQUF5RTtZQUN6RSxtRUFBbUU7WUFDbkUsd0VBQXdFO1lBQ3hFLHFFQUFxRTtZQUNyRSxnQ0FBZ0M7WUFDaEMsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtnQkFDbEMsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsNEdBQTRHLENBQUMsQ0FBQztnQkFDM0gsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGdDQUFnQyxDQUFDO2FBQzVEO2lCQUFNO2dCQUNMLGtFQUFrRTtnQkFDbEUsNkRBQTZEO2dCQUM3RCxnQkFBUSxDQUFDLEdBQUcsQ0FBQyw2REFBNkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDcEc7U0FDRjtRQUVELG1FQUFtRTtRQUNuRSxNQUFNLGNBQWMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7S0FDdEM7QUFDSCxDQUFDO0FBbkRELDBCQW1EQztBQUVELFNBQVMsY0FBYyxDQUNyQixVQUF5RixFQUN6RixrQkFBMEMsRUFBRztJQUU3QyxzRUFBc0U7SUFDdEUsdUJBQXVCO0lBQ3ZCLE1BQU0sa0JBQWtCLEdBQUcsZUFBZSxDQUFDLGtCQUFrQixJQUFJLFVBQVUsQ0FBQyxrQkFBa0IsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDO0lBRXZILGtFQUFrRTtJQUNsRSxJQUFJLFVBQVUsQ0FBQyxXQUFXLEtBQUssUUFBUSxJQUFJLGtCQUFrQixLQUFLLFVBQVUsQ0FBQyxrQkFBa0IsRUFBRTtRQUMvRixNQUFNLElBQUksS0FBSyxDQUFDLHdEQUF3RCxVQUFVLENBQUMsa0JBQWtCLFNBQVMsZUFBZSxDQUFDLGtCQUFrQixtQkFBbUIsQ0FBQyxDQUFDO0tBQ3RLO0lBRUQsMERBQTBEO0lBQzFELE9BQU87UUFDTCxHQUFHLFVBQVU7UUFDYixHQUFHLGVBQWU7UUFDbEIsa0JBQWtCLEVBQUUsa0JBQWtCO0tBQ3ZDLENBQUM7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLGNBQWMsQ0FBQyxNQUE0QixFQUFFLEtBQWU7SUFDekUsTUFBTSxJQUFJLEdBQW1EO1FBQzNELE1BQU0sRUFBRSxNQUFNO1FBQ2QsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLElBQUksTUFBTTtRQUM5QixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87UUFDdEIsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1FBQzFCLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSwwQkFBMEI7UUFDMUUsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtRQUMxQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO0tBQ2pCLENBQUM7SUFFRixnQkFBUSxDQUFDLEdBQUcsQ0FBQyxtQ0FBbUMsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUV4RCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFDLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQy9DLE1BQU0sR0FBRyxHQUFHO1FBQ1YsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO1FBQzVCLElBQUksRUFBRSxTQUFTLENBQUMsSUFBSTtRQUNwQixNQUFNLEVBQUUsS0FBSztRQUNiLE9BQU8sRUFBRTtZQUNQLGNBQWMsRUFBRSxFQUFFO1lBQ2xCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQztTQUMxRDtLQUNGLENBQUM7SUFFRixNQUFNLFlBQVksR0FBRztRQUNuQixRQUFRLEVBQUUsQ0FBQztRQUNYLEtBQUssRUFBRSxJQUFJO0tBQ1osQ0FBQztJQUNGLE1BQU0sV0FBVyxDQUFDLFlBQVksRUFBRSxnQkFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsQ0FBQztBQUMvRSxDQUFDO0FBRUQsS0FBSyxVQUFVLHNCQUFzQixDQUFDLE9BQTZCLEVBQUUsWUFBb0I7SUFDdkYsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNyQyxJQUFJO1lBQ0YsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDNUIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1NBQ2Y7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNYO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsR0FBVyxFQUFFLEdBQUcsTUFBYTtJQUMvQyxzQ0FBc0M7SUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQztBQUM5QixDQUFDO0FBU0QsU0FBZ0IsV0FBVyxDQUEwQixPQUFxQixFQUFFLEVBQTRCO0lBQ3RHLE9BQU8sS0FBSyxFQUFFLEdBQUcsRUFBSyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLE9BQU8sSUFBSSxFQUFFO1lBQ1gsSUFBSTtnQkFDRixPQUFPLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDeEI7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRTtvQkFDbkIsTUFBTSxDQUFDLENBQUM7aUJBQ1Q7Z0JBQ0QsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDNUMsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNUO1NBQ0Y7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDO0FBaEJELGtDQWdCQztBQUVELEtBQUssVUFBVSxLQUFLLENBQUMsRUFBVTtJQUM3QixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDakQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG4vLyBmb3IgdW5pdCB0ZXN0c1xuZXhwb3J0IGNvbnN0IGV4dGVybmFsID0ge1xuICBzZW5kSHR0cFJlcXVlc3Q6IGRlZmF1bHRTZW5kSHR0cFJlcXVlc3QsXG4gIGxvZzogZGVmYXVsdExvZyxcbiAgaW5jbHVkZVN0YWNrVHJhY2VzOiB0cnVlLFxuICB1c2VySGFuZGxlckluZGV4OiAnLi9pbmRleCcsXG59O1xuXG5jb25zdCBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUiA9ICdBV1NDREs6OkN1c3RvbVJlc291cmNlUHJvdmlkZXJGcmFtZXdvcms6OkNSRUFURV9GQUlMRUQnO1xuY29uc3QgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpNSVNTSU5HX1BIWVNJQ0FMX0lEJztcblxuZXhwb3J0IHR5cGUgUmVzcG9uc2UgPSBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgSGFuZGxlclJlc3BvbnNlO1xuZXhwb3J0IHR5cGUgSGFuZGxlciA9IChldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCwgY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpID0+IFByb21pc2U8SGFuZGxlclJlc3BvbnNlIHwgdm9pZD47XG5leHBvcnQgdHlwZSBIYW5kbGVyUmVzcG9uc2UgPSB1bmRlZmluZWQgfCB7XG4gIERhdGE/OiBhbnk7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgUmVhc29uPzogc3RyaW5nO1xuICBOb0VjaG8/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIGNvbnRleHQ6IEFXU0xhbWJkYS5Db250ZXh0KSB7XG4gIGNvbnN0IHNhbml0aXplZEV2ZW50ID0geyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH07XG4gIGV4dGVybmFsLmxvZyhKU09OLnN0cmluZ2lmeShzYW5pdGl6ZWRFdmVudCwgdW5kZWZpbmVkLCAyKSk7XG5cbiAgLy8gaWdub3JlIERFTEVURSBldmVudCB3aGVuIHRoZSBwaHlzaWNhbCByZXNvdXJjZSBJRCBpcyB0aGUgbWFya2VyIHRoYXRcbiAgLy8gaW5kaWNhdGVzIHRoYXQgdGhpcyBERUxFVEUgaXMgYSBzdWJzZXF1ZW50IERFTEVURSB0byBhIGZhaWxlZCBDUkVBVEVcbiAgLy8gb3BlcmF0aW9uLlxuICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9PT0gQ1JFQVRFX0ZBSUxFRF9QSFlTSUNBTF9JRF9NQVJLRVIpIHtcbiAgICBleHRlcm5hbC5sb2coJ2lnbm9yaW5nIERFTEVURSBldmVudCBjYXVzZWQgYnkgYSBmYWlsZWQgQ1JFQVRFIGV2ZW50Jyk7XG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBpbnZva2UgdGhlIHVzZXIgaGFuZGxlci4gdGhpcyBpcyBpbnRlbnRpb25hbGx5IGluc2lkZSB0aGUgdHJ5LWNhdGNoIHRvXG4gICAgLy8gZW5zdXJlIHRoYXQgaWYgdGhlcmUgaXMgYW4gZXJyb3IgaXQncyByZXBvcnRlZCBhcyBhIGZhaWx1cmUgdG9cbiAgICAvLyBjbG91ZGZvcm1hdGlvbiAob3RoZXJ3aXNlIGNmbiB3YWl0cykuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCB1c2VySGFuZGxlcjogSGFuZGxlciA9IHJlcXVpcmUoZXh0ZXJuYWwudXNlckhhbmRsZXJJbmRleCkuaGFuZGxlcjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB1c2VySGFuZGxlcihzYW5pdGl6ZWRFdmVudCwgY29udGV4dCk7XG5cbiAgICAvLyB2YWxpZGF0ZSB1c2VyIHJlc3BvbnNlIGFuZCBjcmVhdGUgdGhlIGNvbWJpbmVkIGV2ZW50XG4gICAgY29uc3QgcmVzcG9uc2VFdmVudCA9IHJlbmRlclJlc3BvbnNlKGV2ZW50LCByZXN1bHQpO1xuXG4gICAgLy8gc3VibWl0IHRvIGNmbiBhcyBzdWNjZXNzXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCByZXNwb25zZUV2ZW50KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgY29uc3QgcmVzcDogUmVzcG9uc2UgPSB7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIFJlYXNvbjogZXh0ZXJuYWwuaW5jbHVkZVN0YWNrVHJhY2VzID8gZS5zdGFjayA6IGUubWVzc2FnZSxcbiAgICB9O1xuXG4gICAgaWYgKCFyZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCkge1xuICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgLy8gaGF2ZSBhIHBoeXNpY2FsIHJlc291cmNlIGlkLiBpbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXF1ZW50IERFTEVURVxuICAgICAgLy8gb3BlcmF0aW9uIGRvZXMgbm90IGhhdmUgYW55IG1lYW5pbmcsIGFuZCB3aWxsIGxpa2VseSBmYWlsIGFzIHdlbGwuIHRvXG4gICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgIC8vIGlnbm9yZSB0aGUgc3Vic2VxdWVudCBERUxFVEUuXG4gICAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnKSB7XG4gICAgICAgIGV4dGVybmFsLmxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICByZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gb3RoZXJ3aXNlLCBpZiBQaHlzaWNhbFJlc291cmNlSWQgaXMgbm90IHNwZWNpZmllZCwgc29tZXRoaW5nIGlzXG4gICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgZXh0ZXJuYWwubG9nKGBFUlJPUjogTWFsZm9ybWVkIGV2ZW50LiBcIlBoeXNpY2FsUmVzb3VyY2VJZFwiIGlzIHJlcXVpcmVkOiAke0pTT04uc3RyaW5naWZ5KGV2ZW50KX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyB0aGlzIGlzIGFuIGFjdHVhbCBlcnJvciwgZmFpbCB0aGUgYWN0aXZpdHkgYWx0b2dldGhlciBhbmQgZXhpc3QuXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ0ZBSUxFRCcsIHJlc3ApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlbmRlclJlc3BvbnNlKFxuICBjZm5SZXF1ZXN0OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgeyBQaHlzaWNhbFJlc291cmNlSWQ/OiBzdHJpbmcgfSxcbiAgaGFuZGxlclJlc3BvbnNlOiB2b2lkIHwgSGFuZGxlclJlc3BvbnNlID0geyB9KTogUmVzcG9uc2Uge1xuXG4gIC8vIGlmIHBoeXNpY2FsIElEIGlzIG5vdCByZXR1cm5lZCwgd2UgaGF2ZSBzb21lIGRlZmF1bHRzIGZvciB5b3UgYmFzZWRcbiAgLy8gb24gdGhlIHJlcXVlc3QgdHlwZS5cbiAgY29uc3QgcGh5c2ljYWxSZXNvdXJjZUlkID0gaGFuZGxlclJlc3BvbnNlLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlJlcXVlc3RJZDtcblxuICAvLyBpZiB3ZSBhcmUgaW4gREVMRVRFIGFuZCBwaHlzaWNhbCBJRCB3YXMgY2hhbmdlZCwgaXQncyBhbiBlcnJvci5cbiAgaWYgKGNmblJlcXVlc3QuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIHBoeXNpY2FsUmVzb3VyY2VJZCAhPT0gY2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERFTEVURTogY2Fubm90IGNoYW5nZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSBcIiR7Y2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWR9XCIgdG8gXCIke2hhbmRsZXJSZXNwb25zZS5QaHlzaWNhbFJlc291cmNlSWR9XCIgZHVyaW5nIGRlbGV0aW9uYCk7XG4gIH1cblxuICAvLyBtZXJnZSByZXF1ZXN0IGV2ZW50IGFuZCByZXN1bHQgZXZlbnQgKHJlc3VsdCBwcmV2YWlscykuXG4gIHJldHVybiB7XG4gICAgLi4uY2ZuUmVxdWVzdCxcbiAgICAuLi5oYW5kbGVyUmVzcG9uc2UsXG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN1Ym1pdFJlc3BvbnNlKHN0YXR1czogJ1NVQ0NFU1MnIHwgJ0ZBSUxFRCcsIGV2ZW50OiBSZXNwb25zZSkge1xuICBjb25zdCBqc29uOiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlID0ge1xuICAgIFN0YXR1czogc3RhdHVzLFxuICAgIFJlYXNvbjogZXZlbnQuUmVhc29uID8/IHN0YXR1cyxcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkIHx8IE1JU1NJTkdfUEhZU0lDQUxfSURfTUFSS0VSLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBOb0VjaG86IGV2ZW50Lk5vRWNobyxcbiAgICBEYXRhOiBldmVudC5EYXRhLFxuICB9O1xuXG4gIGV4dGVybmFsLmxvZygnc3VibWl0IHJlc3BvbnNlIHRvIGNsb3VkZm9ybWF0aW9uJywganNvbik7XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoanNvbik7XG4gIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShldmVudC5SZXNwb25zZVVSTCk7XG4gIGNvbnN0IHJlcSA9IHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogQnVmZmVyLmJ5dGVMZW5ndGgocmVzcG9uc2VCb2R5LCAndXRmOCcpLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3QgcmV0cnlPcHRpb25zID0ge1xuICAgIGF0dGVtcHRzOiA1LFxuICAgIHNsZWVwOiAxMDAwLFxuICB9O1xuICBhd2FpdCB3aXRoUmV0cmllcyhyZXRyeU9wdGlvbnMsIGV4dGVybmFsLnNlbmRIdHRwUmVxdWVzdCkocmVxLCByZXNwb25zZUJvZHkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0U2VuZEh0dHBSZXF1ZXN0KG9wdGlvbnM6IGh0dHBzLlJlcXVlc3RPcHRpb25zLCByZXNwb25zZUJvZHk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCBfID0+IHJlc29sdmUoKSk7XG4gICAgICByZXF1ZXN0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICByZXF1ZXN0LndyaXRlKHJlc3BvbnNlQm9keSk7XG4gICAgICByZXF1ZXN0LmVuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWZhdWx0TG9nKGZtdDogc3RyaW5nLCAuLi5wYXJhbXM6IGFueVtdKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gIGNvbnNvbGUubG9nKGZtdCwgLi4ucGFyYW1zKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXRyeU9wdGlvbnMge1xuICAvKiogSG93IG1hbnkgcmV0cmllcyAod2lsbCBhdCBsZWFzdCB0cnkgb25jZSkgKi9cbiAgcmVhZG9ubHkgYXR0ZW1wdHM6IG51bWJlcjtcbiAgLyoqIFNsZWVwIGJhc2UsIGluIG1zICovXG4gIHJlYWRvbmx5IHNsZWVwOiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB3aXRoUmV0cmllczxBIGV4dGVuZHMgQXJyYXk8YW55PiwgQj4ob3B0aW9uczogUmV0cnlPcHRpb25zLCBmbjogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+KTogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+IHtcbiAgcmV0dXJuIGFzeW5jICguLi54czogQSkgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IG9wdGlvbnMuYXR0ZW1wdHM7XG4gICAgbGV0IG1zID0gb3B0aW9ucy5zbGVlcDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGZuKC4uLnhzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGF0dGVtcHRzLS0gPD0gMCkge1xuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgc2xlZXAoTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbXMpKTtcbiAgICAgICAgbXMgKj0gMjtcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChvaykgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/index.js new file mode 100644 index 0000000000000..013bcaffd8fe5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/index.js @@ -0,0 +1 @@ +"use strict";var I=Object.create;var t=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var G=(r,e)=>{for(var o in e)t(r,o,{get:e[o],enumerable:!0})},n=(r,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of P(e))!l.call(r,s)&&s!==o&&t(r,s,{get:()=>e[s],enumerable:!(i=y(e,s))||i.enumerable});return r};var R=(r,e,o)=>(o=r!=null?I(g(r)):{},n(e||!r||!r.__esModule?t(o,"default",{value:r,enumerable:!0}):o,r)),S=r=>n(t({},"__esModule",{value:!0}),r);var k={};G(k,{handler:()=>f});module.exports=S(k);var a=R(require("@aws-sdk/client-ec2")),u=new a.EC2({});function c(r,e){return{GroupId:r,IpPermissions:[{UserIdGroupPairs:[{GroupId:r,UserId:e}],IpProtocol:"-1"}]}}function d(r){return{GroupId:r,IpPermissions:[{IpRanges:[{CidrIp:"0.0.0.0/0"}],IpProtocol:"-1"}]}}async function f(r){let e=r.ResourceProperties.DefaultSecurityGroupId,o=r.ResourceProperties.Account;switch(r.RequestType){case"Create":return p(e,o);case"Update":return h(r);case"Delete":return m(e,o)}}async function h(r){let e=r.OldResourceProperties.DefaultSecurityGroupId,o=r.ResourceProperties.DefaultSecurityGroupId;e!==o&&(await m(e,r.ResourceProperties.Account),await p(o,r.ResourceProperties.Account))}async function p(r,e){try{await u.revokeSecurityGroupEgress(d(r))}catch(o){if(o.name!=="InvalidPermission.NotFound")throw o}try{await u.revokeSecurityGroupIngress(c(r,e))}catch(o){if(o.name!=="InvalidPermission.NotFound")throw o}}async function m(r,e){await u.authorizeSecurityGroupIngress(c(r,e)),await u.authorizeSecurityGroupEgress(d(r))}0&&(module.exports={handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/cdk.out index 560dae10d018f..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"33.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ-deployment-alarms.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ-deployment-alarms.assets.json index 4d6d4085b728c..e2d09d758c206 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ-deployment-alarms.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ-deployment-alarms.assets.json @@ -1,20 +1,20 @@ { - "version": "33.0.0", + "version": "36.0.0", "files": { - "18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837": { + "4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292": { "source": { - "path": "asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837", + "path": "asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837.zip", + "objectKey": "4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "e62aa756e86e9b47c7f2741081bcf8bad768b60bf287eb2b43c5e3fbd07eb181": { + "46a7619aba43b373438c768b8cc4d633a608077210d907bfac8ed3080b0451ee": { "source": { "path": "integ-deployment-alarms.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "e62aa756e86e9b47c7f2741081bcf8bad768b60bf287eb2b43c5e3fbd07eb181.json", + "objectKey": "46a7619aba43b373438c768b8cc4d633a608077210d907bfac8ed3080b0451ee.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ-deployment-alarms.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ-deployment-alarms.template.json index 69534ef4db1ff..9b609921e9615 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ-deployment-alarms.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ-deployment-alarms.template.json @@ -489,7 +489,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837.zip" + "S3Key": "4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292.zip" }, "Timeout": 900, "MemorySize": 128, @@ -943,7 +943,7 @@ "ASGDrainECSHookFunctionServiceRoleC12963BB" ] }, - "ASGDrainECSHookFunctionAllowInvokeintegdeploymentalarmsASGLifecycleHookDrainHookTopic48A952B0CEFB05B2": { + "ASGDrainECSHookFunctionAllowInvokeintegdeploymentalarmsASGLifecycleHookDrainHookTopicLifecycleHookDrainHook25B363C231FF9955": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -955,11 +955,11 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, - "ASGDrainECSHookFunctionTopicD6FC59F7": { + "ASGDrainECSHookFunctionTopicLifecycleHookDrainHook8B240409": { "Type": "AWS::SNS::Subscription", "Properties": { "Endpoint": { @@ -970,11 +970,11 @@ }, "Protocol": "lambda", "TopicArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, - "ASGLifecycleHookDrainHookTopicA8AD4ACB": { + "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -1017,7 +1017,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } ], @@ -1041,7 +1041,7 @@ "HeartbeatTimeout": 300, "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ.json index e2ab5e380f2ba..33e8fdc13a284 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "33.0.0", + "version": "36.0.0", "testCases": { "DeploymentAlarms/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/manifest.json index 8f0170b620cd5..59f29361ac846 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "33.0.0", + "version": "36.0.0", "artifacts": { "integ-deployment-alarms.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "integ-deployment-alarms.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}/e62aa756e86e9b47c7f2741081bcf8bad768b60bf287eb2b43c5e3fbd07eb181.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/46a7619aba43b373438c768b8cc4d633a608077210d907bfac8ed3080b0451ee.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -255,22 +256,22 @@ "data": "ASGDrainECSHookFunction5F24CF4D" } ], - "/integ-deployment-alarms/ASG/DrainECSHook/Function/AllowInvoke:integdeploymentalarmsASGLifecycleHookDrainHookTopic48A952B0": [ + "/integ-deployment-alarms/ASG/DrainECSHook/Function/AllowInvoke:integdeploymentalarmsASGLifecycleHookDrainHookTopicLifecycleHookDrainHook25B363C2": [ { "type": "aws:cdk:logicalId", - "data": "ASGDrainECSHookFunctionAllowInvokeintegdeploymentalarmsASGLifecycleHookDrainHookTopic48A952B0CEFB05B2" + "data": "ASGDrainECSHookFunctionAllowInvokeintegdeploymentalarmsASGLifecycleHookDrainHookTopicLifecycleHookDrainHook25B363C231FF9955" } ], - "/integ-deployment-alarms/ASG/DrainECSHook/Function/Topic/Resource": [ + "/integ-deployment-alarms/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ASGDrainECSHookFunctionTopicD6FC59F7" + "data": "ASGDrainECSHookFunctionTopicLifecycleHookDrainHook8B240409" } ], - "/integ-deployment-alarms/ASG/LifecycleHookDrainHook/Topic/Resource": [ + "/integ-deployment-alarms/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "data": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } ], "/integ-deployment-alarms/ASG/LifecycleHookDrainHook/Role/Resource": [ @@ -338,6 +339,33 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "ASGDrainECSHookFunctionAllowInvokeintegdeploymentalarmsASGLifecycleHookDrainHookTopic48A952B0CEFB05B2": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGDrainECSHookFunctionAllowInvokeintegdeploymentalarmsASGLifecycleHookDrainHookTopic48A952B0CEFB05B2", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ASGDrainECSHookFunctionTopicD6FC59F7": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGDrainECSHookFunctionTopicD6FC59F7", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ASGLifecycleHookDrainHookTopicA8AD4ACB": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGLifecycleHookDrainHookTopicA8AD4ACB", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "integ-deployment-alarms" @@ -355,6 +383,7 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "DeploymentAlarmsDefaultTestDeployAssertAFB973D1.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}", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/tree.json index 2b455b4eebc00..037bd1dbcc4dd 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.deployment-alarms.js.snapshot/tree.json @@ -699,7 +699,7 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.CustomResourceProvider", + "fqn": "aws-cdk-lib.CustomResourceProviderBase", "version": "0.0.0" } }, @@ -1346,9 +1346,9 @@ "version": "0.0.0" } }, - "AllowInvoke:integdeploymentalarmsASGLifecycleHookDrainHookTopic48A952B0": { - "id": "AllowInvoke:integdeploymentalarmsASGLifecycleHookDrainHookTopic48A952B0", - "path": "integ-deployment-alarms/ASG/DrainECSHook/Function/AllowInvoke:integdeploymentalarmsASGLifecycleHookDrainHookTopic48A952B0", + "AllowInvoke:integdeploymentalarmsASGLifecycleHookDrainHookTopicLifecycleHookDrainHook25B363C2": { + "id": "AllowInvoke:integdeploymentalarmsASGLifecycleHookDrainHookTopicLifecycleHookDrainHook25B363C2", + "path": "integ-deployment-alarms/ASG/DrainECSHook/Function/AllowInvoke:integdeploymentalarmsASGLifecycleHookDrainHookTopicLifecycleHookDrainHook25B363C2", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1361,7 +1361,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, @@ -1370,13 +1370,13 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "integ-deployment-alarms/ASG/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "integ-deployment-alarms/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "integ-deployment-alarms/ASG/DrainECSHook/Function/Topic/Resource", + "path": "integ-deployment-alarms/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { @@ -1388,7 +1388,7 @@ }, "protocol": "lambda", "topicArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, @@ -1412,20 +1412,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.69" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "integ-deployment-alarms/ASG/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "integ-deployment-alarms/ASG/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "integ-deployment-alarms/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "integ-deployment-alarms/ASG/LifecycleHookDrainHook/Topic/Resource", + "path": "integ-deployment-alarms/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1507,7 +1507,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } ], @@ -1551,7 +1551,7 @@ "heartbeatTimeout": 300, "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" }, "roleArn": { "Fn::GetAtt": [ @@ -1798,7 +1798,7 @@ "path": "DeploymentAlarms/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.69" + "version": "10.3.0" } }, "DeployAssert": { @@ -1844,7 +1844,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.69" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/aws-ecs-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/aws-ecs-integ.assets.json index e6ab36635fda8..008a680337fd1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/aws-ecs-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/aws-ecs-integ.assets.json @@ -66,7 +66,7 @@ } } }, - "3e48862248dd9b65e36eed1380dded66b06cbad1a5a62664d5932070b1881a35": { + "aacb72361b48be8621b8199c61cc6aa237a430134e51e589618ced1067930731": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -74,7 +74,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "3e48862248dd9b65e36eed1380dded66b06cbad1a5a62664d5932070b1881a35.json", + "objectKey": "aacb72361b48be8621b8199c61cc6aa237a430134e51e589618ced1067930731.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/aws-ecs-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/aws-ecs-integ.template.json index 9e657b87241e7..f9ebbbca34aa5 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/aws-ecs-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/aws-ecs-integ.template.json @@ -937,7 +937,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -949,11 +949,11 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { "Endpoint": { @@ -964,11 +964,11 @@ }, "Protocol": "lambda", "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -1011,7 +1011,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1035,7 +1035,7 @@ "HeartbeatTimeout": 300, "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/manifest.json index b78be6083bf43..363e68d7b03f4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/manifest.json @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/3e48862248dd9b65e36eed1380dded66b06cbad1a5a62664d5932070b1881a35.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/aacb72361b48be8621b8199c61cc6aa237a430134e51e589618ced1067930731.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -262,22 +262,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -325,10 +325,7 @@ "/aws-ecs-integ/EnvFileDeployment/AwsCliLayer/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EnvFileDeploymentAwsCliLayerA8FC897D", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" - ] + "data": "EnvFileDeploymentAwsCliLayerA8FC897D" } ], "/aws-ecs-integ/EnvFileDeployment/CustomResource/Default": [ @@ -378,6 +375,33 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "aws-ecs-integ" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/tree.json index 878364c959fbd..1c08af2309d19 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.environment-file.js.snapshot/tree.json @@ -1371,9 +1371,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": { - "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", + "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": { + "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1386,7 +1386,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1395,13 +1395,13 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { @@ -1413,7 +1413,7 @@ }, "protocol": "lambda", "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1444,13 +1444,13 @@ "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1532,7 +1532,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1576,7 +1576,7 @@ "heartbeatTimeout": 300, "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/aws-ecs-integ-exec-command.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/aws-ecs-integ-exec-command.assets.json index ad94bfe3dbafb..b3cf465ed8228 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/aws-ecs-integ-exec-command.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/aws-ecs-integ-exec-command.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "394a69951bd3f856d078c416187f54e4212598a095bc3ae6b3420ed481988218": { + "ef2801557ae4ce22df4e22a5c2b053768d9396ecb79a890753280fe53566a8a3": { "source": { "path": "aws-ecs-integ-exec-command.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "394a69951bd3f856d078c416187f54e4212598a095bc3ae6b3420ed481988218.json", + "objectKey": "ef2801557ae4ce22df4e22a5c2b053768d9396ecb79a890753280fe53566a8a3.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/aws-ecs-integ-exec-command.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/aws-ecs-integ-exec-command.template.json index db9a3a39e45b5..7a80e0f90d70f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/aws-ecs-integ-exec-command.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/aws-ecs-integ-exec-command.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -733,8 +733,6 @@ "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "Ec2ClusterDefaultAutoScalingGroupLaunchTemplate346F58BE" @@ -746,6 +744,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -901,12 +901,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -915,6 +909,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -929,7 +929,7 @@ "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3" ] }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C92983E1AD32": { + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook36745FE6EAA71EDA": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -941,26 +941,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6": { + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook235709FD": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" - }, "Endpoint": { "Fn::GetAtt": [ "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } }, - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30": { + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -1003,7 +1003,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } ], @@ -1023,11 +1023,11 @@ "AutoScalingGroupName": { "Ref": "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/integ.json index 2d8b3c4f3bdfe..640fd439d86e6 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.exec-command": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/manifest.json index 2e3c3ce0feb70..0e34a3d01a655 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-exec-command.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-exec-command.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}/394a69951bd3f856d078c416187f54e4212598a095bc3ae6b3420ed481988218.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/ef2801557ae4ce22df4e22a5c2b053768d9396ecb79a890753280fe53566a8a3.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -249,22 +250,22 @@ "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31" } ], - "/aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C929": [ + "/aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook36745FE6": [ { "type": "aws:cdk:logicalId", - "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C92983E1AD32" + "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook36745FE6EAA71EDA" } ], - "/aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6" + "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook235709FD" } ], - "/aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "data": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } ], "/aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -327,10 +328,28 @@ "data": "CheckBootstrapVersion" } ], - "Ec2ClusterDefaultAutoScalingGroupLaunchTemplateProfileA74899D4": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C92983E1AD32": [ { "type": "aws:cdk:logicalId", - "data": "Ec2ClusterDefaultAutoScalingGroupLaunchTemplateProfileA74899D4", + "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C92983E1AD32", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6": [ + { + "type": "aws:cdk:logicalId", + "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30": [ + { + "type": "aws:cdk:logicalId", + "data": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/tree.json index 6da5a854cf706..3e674c1e32f94 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.exec-command.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-exec-command/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-exec-command/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -1045,6 +1045,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -1144,8 +1152,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "Ec2ClusterDefaultAutoScalingGroupLaunchTemplate346F58BE" @@ -1157,6 +1163,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1364,12 +1372,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1378,6 +1380,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1393,9 +1401,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C929": { - "id": "AllowInvoke:awsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C929", - "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic05F8C929", + "AllowInvoke:awsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook36745FE6": { + "id": "AllowInvoke:awsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook36745FE6", + "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegexeccommandEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook36745FE6", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1408,7 +1416,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } }, @@ -1417,25 +1425,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" - }, "endpoint": { "Fn::GetAtt": [ "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } }, @@ -1459,20 +1467,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-exec-command/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1554,7 +1562,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } ], @@ -1594,11 +1602,11 @@ "autoScalingGroupName": { "Ref": "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" }, "roleArn": { "Fn::GetAtt": [ @@ -1939,7 +1947,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.assets.json index 82ac259be7c99..dd36f00fcf0c4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.assets.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { "2ca891b3a73a4a36630bba20580e3390a104d2ac9ff1f22a6bcadf575f8a5a61": { "source": { @@ -14,7 +14,7 @@ } } }, - "25039895d2a6fbaa22673106b7d6e5bd38323ef33f56e2cbe539b440bde5d8d5": { + "271ebf40c677833632b02a89d4e504ee8439443a63e1d0ccab8ec0ca4bb2a452": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "25039895d2a6fbaa22673106b7d6e5bd38323ef33f56e2cbe539b440bde5d8d5.json", + "objectKey": "271ebf40c677833632b02a89d4e504ee8439443a63e1d0ccab8ec0ca4bb2a452.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.template.json index 9ec17a6f8aaaa..faea9cc205c12 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/aws-ecs-integ.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -589,8 +589,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/integ.json index 2d33ad760f3bb..6b45e8119add9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.firelens-s3-config": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/manifest.json index ebc77a721b1f6..d15cf71453f43 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ.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}/25039895d2a6fbaa22673106b7d6e5bd38323ef33f56e2cbe539b440bde5d8d5.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/271ebf40c677833632b02a89d4e504ee8439443a63e1d0ccab8ec0ca4bb2a452.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -333,10 +334,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/tree.json index 090569a58d157..b8f92514926ee 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.firelens-s3-config.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": { - "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", + "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": { + "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1577,7 +1585,15 @@ "auto_create_group": "true", "log_stream_prefix": "nginx" } - } + }, + "environment": [ + { + "name": "AWS_REGION", + "value": { + "Ref": "AWS::Region" + } + } + ] } ], "executionRoleArn": { @@ -1963,7 +1979,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/aws-ecs-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/aws-ecs-integ.assets.json index 3b6232b3cbef8..024daa7fcd763 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/aws-ecs-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/aws-ecs-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "97a9d0120f4d0bcb2ae91e291dd39328d03094fdf919b9e7c397167ee480167c": { + "a121020af7357035cfe6c00f8af4cb288b1f60dbfc0ee28340a4e67fcc71fb58": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "97a9d0120f4d0bcb2ae91e291dd39328d03094fdf919b9e7c397167ee480167c.json", + "objectKey": "a121020af7357035cfe6c00f8af4cb288b1f60dbfc0ee28340a4e67fcc71fb58.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/aws-ecs-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/aws-ecs-integ.template.json index b13e0caba5355..bb0c9a679f9f2 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/aws-ecs-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/aws-ecs-integ.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -615,8 +615,6 @@ "EcsClustergravitonclusterASG869F3168": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "2", - "MinSize": "2", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClustergravitonclusterLaunchTemplate46854EA7" @@ -628,6 +626,8 @@ ] } }, + "MaxSize": "2", + "MinSize": "2", "Tags": [ { "Key": "Name", @@ -783,12 +783,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -797,6 +791,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -811,7 +811,7 @@ "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764" ] }, - "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3": { + "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D84710EEC5": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -823,26 +823,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } }, - "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43": { + "EcsClustergravitonclusterDrainECSHookFunctionTopicLifecycleHookDrainHook4A479900": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClustergravitonclusterDrainECSHookFunctionB606E681", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } }, - "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": { + "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -885,7 +885,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } ], @@ -905,11 +905,11 @@ "AutoScalingGroupName": { "Ref": "EcsClustergravitonclusterASG869F3168" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/cdk.out index f0b901e7c06e5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/integ.json index 5b121da2aedeb..f2ffb5b10801f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.graviton-bottlerocket": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/manifest.json index 9002072247f33..a035e8c283704 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ.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}/97a9d0120f4d0bcb2ae91e291dd39328d03094fdf919b9e7c397167ee480167c.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/a121020af7357035cfe6c00f8af4cb288b1f60dbfc0ee28340a4e67fcc71fb58.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClustergravitonclusterDrainECSHookFunctionB606E681" } ], - "/aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA": [ + "/aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D8": [ { "type": "aws:cdk:logicalId", - "data": "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3" + "data": "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D84710EEC5" } ], - "/aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43" + "data": "EcsClustergravitonclusterDrainECSHookFunctionTopicLifecycleHookDrainHook4A479900" } ], - "/aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "data": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } ], "/aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/Role/Resource": [ @@ -285,10 +286,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClustergravitonclusterLaunchTemplateProfile185F7FB0": [ + "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3": [ { "type": "aws:cdk:logicalId", - "data": "EcsClustergravitonclusterLaunchTemplateProfile185F7FB0", + "data": "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/tree.json index d50b2b4b37b70..c69031caba4c9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton-bottlerocket.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -880,6 +880,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LaunchTemplate", @@ -979,8 +987,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "2", - "minSize": "2", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClustergravitonclusterLaunchTemplate46854EA7" @@ -992,6 +998,8 @@ ] } }, + "maxSize": "2", + "minSize": "2", "tags": [ { "key": "Name", @@ -1199,12 +1207,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1213,6 +1215,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1228,9 +1236,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA": { - "id": "AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA", + "AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D8": { + "id": "AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D8", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D8", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1243,7 +1251,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } }, @@ -1252,25 +1260,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" - }, "endpoint": { "Fn::GetAtt": [ "EcsClustergravitonclusterDrainECSHookFunctionB606E681", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } }, @@ -1294,20 +1302,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1389,7 +1397,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } ], @@ -1429,11 +1437,11 @@ "autoScalingGroupName": { "Ref": "EcsClustergravitonclusterASG869F3168" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" }, "roleArn": { "Fn::GetAtt": [ @@ -1509,7 +1517,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/aws-ecs-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/aws-ecs-integ.assets.json index 0796766d3f311..2e7b399412624 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/aws-ecs-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/aws-ecs-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "6156adc5e94052a67460bd0e7561176c2091a0c1e48d3cc5d4198fad8289578a": { + "b30554ea58ff1cf12065feab53854e54cab29fcad1c9236a481d73b5d390632a": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "6156adc5e94052a67460bd0e7561176c2091a0c1e48d3cc5d4198fad8289578a.json", + "objectKey": "b30554ea58ff1cf12065feab53854e54cab29fcad1c9236a481d73b5d390632a.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/aws-ecs-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/aws-ecs-integ.template.json index 5ab59606da8e5..cbff30eb72bfe 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/aws-ecs-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/aws-ecs-integ.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -589,8 +589,6 @@ "EcsClustergravitonclusterASG869F3168": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "2", - "MinSize": "2", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClustergravitonclusterLaunchTemplate46854EA7" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "2", + "MinSize": "2", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764" ] }, - "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3": { + "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D84710EEC5": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } }, - "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43": { + "EcsClustergravitonclusterDrainECSHookFunctionTopicLifecycleHookDrainHook4A479900": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClustergravitonclusterDrainECSHookFunctionB606E681", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } }, - "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": { + "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClustergravitonclusterASG869F3168" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/cdk.out index f0b901e7c06e5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/integ.json index 4832c36b741e0..6191e7c05063a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.graviton": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/manifest.json index eabe048922a12..d3d385cb6b501 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ.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}/6156adc5e94052a67460bd0e7561176c2091a0c1e48d3cc5d4198fad8289578a.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/b30554ea58ff1cf12065feab53854e54cab29fcad1c9236a481d73b5d390632a.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClustergravitonclusterDrainECSHookFunctionB606E681" } ], - "/aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA": [ + "/aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D8": [ { "type": "aws:cdk:logicalId", - "data": "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3" + "data": "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D84710EEC5" } ], - "/aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43" + "data": "EcsClustergravitonclusterDrainECSHookFunctionTopicLifecycleHookDrainHook4A479900" } ], - "/aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "data": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } ], "/aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/Role/Resource": [ @@ -285,10 +286,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClustergravitonclusterLaunchTemplateProfile185F7FB0": [ + "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3": [ { "type": "aws:cdk:logicalId", - "data": "EcsClustergravitonclusterLaunchTemplateProfile185F7FB0", + "data": "EcsClustergravitonclusterDrainECSHookFunctionAllowInvokeawsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA50D91BA3", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClustergravitonclusterDrainECSHookFunctionTopic65B3FD43", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/tree.json index 2b448c85225a7..011482556a03b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.graviton.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "2", - "minSize": "2", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClustergravitonclusterLaunchTemplate46854EA7" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "2", + "minSize": "2", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClustergravitonclusterDrainECSHookFunctionServiceRole26D97764", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA": { - "id": "AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicF44E68AA", + "AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D8": { + "id": "AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D8", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHookBA9785D8", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" - }, "endpoint": { "Fn::GetAtt": [ "EcsClustergravitonclusterDrainECSHookFunctionB606E681", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/graviton-cluster/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClustergravitonclusterASG869F3168" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopic0A778AAC" + "Ref": "EcsClustergravitonclusterLifecycleHookDrainHookTopicLifecycleHookDrainHook3AA40EA0" }, "roleArn": { "Fn::GetAtt": [ @@ -1483,7 +1491,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/aws-ecs-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/aws-ecs-integ.assets.json index 65f72d8e5b1a5..247e46f914927 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/aws-ecs-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/aws-ecs-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "3882a373abea4fec29f56221c708dce2675f410833231d093a7c9e3463c96f1b": { + "151e3665cf0dca19e845e8608c1eb64a8c45af1ea2fcdc1c08a15de12530c41c": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "3882a373abea4fec29f56221c708dce2675f410833231d093a7c9e3463c96f1b.json", + "objectKey": "151e3665cf0dca19e845e8608c1eb64a8c45af1ea2fcdc1c08a15de12530c41c.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/aws-ecs-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/aws-ecs-integ.template.json index a59fc8fb4881b..8aec3d014c6cf 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/aws-ecs-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/aws-ecs-integ.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -589,8 +589,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ @@ -925,12 +925,12 @@ "Value": "value" }, { - "Name": "AWS_REGION", - "Value": { - "Ref": "AWS::Region" - } + "Name": "AWS_REGION", + "Value": { + "Ref": "AWS::Region" + } } - ], + ], "Essential": true, "Image": "amazon/amazon-ecs-sample", "Memory": 256, @@ -1037,7 +1037,6 @@ "ServiceSecurityGroupfromawsecsintegLBSecurityGroupC30F5EB480CD1B9463": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { - "IpProtocol": "tcp", "Description": "Load balancer to target", "FromPort": 80, "GroupId": { @@ -1046,6 +1045,7 @@ "GroupId" ] }, + "IpProtocol": "tcp", "SourceSecurityGroupId": { "Fn::GetAtt": [ "LBSecurityGroup8A41EA2B", @@ -1114,13 +1114,6 @@ "LBSecurityGrouptoawsecsintegServiceSecurityGroup48EE4368807B287D7F": { "Type": "AWS::EC2::SecurityGroupEgress", "Properties": { - "GroupId": { - "Fn::GetAtt": [ - "LBSecurityGroup8A41EA2B", - "GroupId" - ] - }, - "IpProtocol": "tcp", "Description": "Load balancer to target", "DestinationSecurityGroupId": { "Fn::GetAtt": [ @@ -1129,6 +1122,13 @@ ] }, "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "LBSecurityGroup8A41EA2B", + "GroupId" + ] + }, + "IpProtocol": "tcp", "ToPort": 80 } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/integ.json index 57c1c28a23f36..6cc26e5eed17b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.lb-awsvpc-nw": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/manifest.json index feac9feb04dc0..37a763ffa96ad 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ.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}/3882a373abea4fec29f56221c708dce2675f410833231d093a7c9e3463c96f1b.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/151e3665cf0dca19e845e8608c1eb64a8c45af1ea2fcdc1c08a15de12530c41c.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -351,10 +352,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/tree.json index 83bfb41aee647..3ac9eb4a89a22 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-awsvpc-nw.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": { - "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", + "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": { + "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1520,6 +1528,18 @@ "containerPort": 80, "protocol": "tcp" } + ], + "environment": [ + { + "name": "SOME_VARIABLE", + "value": "value" + }, + { + "name": "AWS_REGION", + "value": { + "Ref": "AWS::Region" + } + } ] } ], @@ -1655,7 +1675,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupIngress", "aws:cdk:cloudformation:props": { - "ipProtocol": "tcp", "description": "Load balancer to target", "fromPort": 80, "groupId": { @@ -1664,6 +1683,7 @@ "GroupId" ] }, + "ipProtocol": "tcp", "sourceSecurityGroupId": { "Fn::GetAtt": [ "LBSecurityGroup8A41EA2B", @@ -1767,13 +1787,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupEgress", "aws:cdk:cloudformation:props": { - "groupId": { - "Fn::GetAtt": [ - "LBSecurityGroup8A41EA2B", - "GroupId" - ] - }, - "ipProtocol": "tcp", "description": "Load balancer to target", "destinationSecurityGroupId": { "Fn::GetAtt": [ @@ -1782,6 +1795,13 @@ ] }, "fromPort": 80, + "groupId": { + "Fn::GetAtt": [ + "LBSecurityGroup8A41EA2B", + "GroupId" + ] + }, + "ipProtocol": "tcp", "toPort": 80 } }, @@ -1908,7 +1928,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/aws-ecs-integ-ecs.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/aws-ecs-integ-ecs.assets.json index 5161cfd7a08e8..aff7a190070b8 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/aws-ecs-integ-ecs.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/aws-ecs-integ-ecs.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "70bc1efe0c5f0b52c7d3e15e6a0cd1e0b8233bb022da71cf7e055e1b728c04c8": { + "65a7d319526aa6521ca0555c25143aafe2c5d4c3a5f41670d9267f26f575ad7a": { "source": { "path": "aws-ecs-integ-ecs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "70bc1efe0c5f0b52c7d3e15e6a0cd1e0b8233bb022da71cf7e055e1b728c04c8.json", + "objectKey": "65a7d319526aa6521ca0555c25143aafe2c5d4c3a5f41670d9267f26f575ad7a.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/aws-ecs-integ-ecs.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/aws-ecs-integ-ecs.template.json index a7a1bdfa0c9f5..820cff725ee85 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/aws-ecs-integ-ecs.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/aws-ecs-integ-ecs.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -419,7 +419,6 @@ "EcsClusterDefaultAutoScalingGroupInstanceSecurityGroupfromawsecsintegecsLBSecurityGroup7DA9012980800B834EB8": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { - "IpProtocol": "tcp", "Description": "Load balancer to target", "FromPort": 8080, "GroupId": { @@ -428,6 +427,7 @@ "GroupId" ] }, + "IpProtocol": "tcp", "SourceSecurityGroupId": { "Fn::GetAtt": [ "LBSecurityGroup8A41EA2B", @@ -610,8 +610,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -623,6 +621,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -778,12 +778,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -792,6 +786,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -806,7 +806,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -818,26 +818,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -880,7 +880,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -900,11 +900,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ @@ -1060,13 +1060,6 @@ "LBSecurityGrouptoawsecsintegecsEcsClusterDefaultAutoScalingGroupInstanceSecurityGroupE3116410808033398DFA": { "Type": "AWS::EC2::SecurityGroupEgress", "Properties": { - "GroupId": { - "Fn::GetAtt": [ - "LBSecurityGroup8A41EA2B", - "GroupId" - ] - }, - "IpProtocol": "tcp", "Description": "Load balancer to target", "DestinationSecurityGroupId": { "Fn::GetAtt": [ @@ -1075,6 +1068,13 @@ ] }, "FromPort": 8080, + "GroupId": { + "Fn::GetAtt": [ + "LBSecurityGroup8A41EA2B", + "GroupId" + ] + }, + "IpProtocol": "tcp", "ToPort": 8080 } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/integ.json index 8b44f69ecd532..213de545637ae 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.lb-bridge-nw": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/manifest.json index a0f4a43ecd4f8..b0875d02d9673 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-ecs.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-ecs.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}/70bc1efe0c5f0b52c7d3e15e6a0cd1e0b8233bb022da71cf7e055e1b728c04c8.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/65a7d319526aa6521ca0555c25143aafe2c5d4c3a5f41670d9267f26f575ad7a.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -237,22 +238,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -345,10 +346,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/tree.json index 74442e52cd610..6bf9544c6b527 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.lb-bridge-nw.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -711,7 +711,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupIngress", "aws:cdk:cloudformation:props": { - "ipProtocol": "tcp", "description": "Load balancer to target", "fromPort": 8080, "groupId": { @@ -720,6 +719,7 @@ "GroupId" ] }, + "ipProtocol": "tcp", "sourceSecurityGroupId": { "Fn::GetAtt": [ "LBSecurityGroup8A41EA2B", @@ -883,6 +883,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -982,8 +990,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -995,6 +1001,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1202,12 +1210,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1216,6 +1218,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1231,9 +1239,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": { - "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", + "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": { + "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1246,7 +1254,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1255,25 +1263,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1297,20 +1305,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1392,7 +1400,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1432,11 +1440,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1713,13 +1721,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupEgress", "aws:cdk:cloudformation:props": { - "groupId": { - "Fn::GetAtt": [ - "LBSecurityGroup8A41EA2B", - "GroupId" - ] - }, - "ipProtocol": "tcp", "description": "Load balancer to target", "destinationSecurityGroupId": { "Fn::GetAtt": [ @@ -1728,6 +1729,13 @@ ] }, "fromPort": 8080, + "groupId": { + "Fn::GetAtt": [ + "LBSecurityGroup8A41EA2B", + "GroupId" + ] + }, + "ipProtocol": "tcp", "toPort": 8080 } }, @@ -1854,7 +1862,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/aws-cdk-ecs-integration-test-stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/aws-cdk-ecs-integration-test-stack.assets.json index 85b61eea25443..ad8fee77402a7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/aws-cdk-ecs-integration-test-stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/aws-cdk-ecs-integration-test-stack.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "0c225ac5ea61f423e7019da6b9738c6a202b64a62a2c2ac911dbf142ab481578": { + "e4b94d730046eed7112df744e97b344803a5eeb3bc20a4afb97d72438382ace2": { "source": { "path": "aws-cdk-ecs-integration-test-stack.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "0c225ac5ea61f423e7019da6b9738c6a202b64a62a2c2ac911dbf142ab481578.json", + "objectKey": "e4b94d730046eed7112df744e97b344803a5eeb3bc20a4afb97d72438382ace2.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/aws-cdk-ecs-integration-test-stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/aws-cdk-ecs-integration-test-stack.template.json index 89b565d0e557e..32be6b1fc5c4f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/aws-cdk-ecs-integration-test-stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/aws-cdk-ecs-integration-test-stack.template.json @@ -18,9 +18,6 @@ "VPCPublicSubnet1SubnetB4246D30": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-cdk-ecs-integration-test-stack/VPC/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "VPCPublicSubnet1RouteTableFEE4B781": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "Tags": [ { "Key": "Name", "Value": "aws-cdk-ecs-integration-test-stack/VPC/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "VPCPublicSubnet1RouteTableAssociation0B0896DC": { @@ -75,12 +75,12 @@ "VPCPublicSubnet1DefaultRoute91CEF279": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VPCPublicSubnet1NATGatewayE0556630": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VPCPublicSubnet2Subnet74179F39": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-cdk-ecs-integration-test-stack/VPC/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "VPCPublicSubnet2RouteTable6F1A15F1": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "Tags": [ { "Key": "Name", "Value": "aws-cdk-ecs-integration-test-stack/VPC/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "VPCPublicSubnet2RouteTableAssociation5A808732": { @@ -183,12 +183,12 @@ "VPCPublicSubnet2DefaultRouteB7481BBA": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VPCPublicSubnet2NATGateway3C070193": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "AllocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VPCPrivateSubnet1Subnet8BCA10E0": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-cdk-ecs-integration-test-stack/VPC/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "VPCPrivateSubnet1RouteTableBE8A6027": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "Tags": [ { "Key": "Name", "Value": "aws-cdk-ecs-integration-test-stack/VPC/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "VPCPrivateSubnet1RouteTableAssociation347902D1": { @@ -291,21 +291,18 @@ "VPCPrivateSubnet1DefaultRouteAE1D6490": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VPCPublicSubnet1NATGatewayE0556630" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" } } }, "VPCPrivateSubnet2SubnetCFCDAA7A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-cdk-ecs-integration-test-stack/VPC/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "VPCPrivateSubnet2RouteTable0A19E10E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "Tags": [ { "Key": "Name", "Value": "aws-cdk-ecs-integration-test-stack/VPC/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "VPCPrivateSubnet2RouteTableAssociation0C73D413": { @@ -360,12 +360,12 @@ "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VPCPublicSubnet2NATGateway3C070193" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" } } }, @@ -383,11 +383,11 @@ "VPCVPCGW99B986DC": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "VPCB9E5F0B4" - }, "InternetGatewayId": { "Ref": "VPCIGWB7E252D3" + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" } } }, @@ -589,8 +589,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572F6CCD921": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB2590F4035E": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/integ.json index 7d8b0c9ef9e41..7b7604df4cc4c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.placement-strategies": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/manifest.json index 7321286d5343a..13d762883d12b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-cdk-ecs-integration-test-stack.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-cdk-ecs-integration-test-stack.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}/0c225ac5ea61f423e7019da6b9738c6a202b64a62a2c2ac911dbf142ab481578.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/e4b94d730046eed7112df744e97b344803a5eeb3bc20a4afb97d72438382ace2.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572": [ + "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB25": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572F6CCD921" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB2590F4035E" } ], - "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -303,10 +304,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572F6CCD921": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572F6CCD921", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/tree.json index f6fbf259c8344..c13d6a4e9b2df 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.placement-strategies.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-cdk-ecs-integration-test-stack/VPC/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "tags": [ { "key": "Name", "value": "aws-cdk-ecs-integration-test-stack/VPC/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, "allocationId": { "Fn::GetAtt": [ "VPCPublicSubnet1EIP6AD938E8", "AllocationId" ] }, + "subnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-cdk-ecs-integration-test-stack/VPC/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "tags": [ { "key": "Name", "value": "aws-cdk-ecs-integration-test-stack/VPC/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, "allocationId": { "Fn::GetAtt": [ "VPCPublicSubnet2EIP4947BC00", "AllocationId" ] }, + "subnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-cdk-ecs-integration-test-stack/VPC/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "tags": [ { "key": "Name", "value": "aws-cdk-ecs-integration-test-stack/VPC/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VPCPublicSubnet1NATGatewayE0556630" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-cdk-ecs-integration-test-stack/VPC/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "tags": [ { "key": "Name", "value": "aws-cdk-ecs-integration-test-stack/VPC/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VPCPublicSubnet2NATGateway3C070193" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "VPCB9E5F0B4" - }, "internetGatewayId": { "Ref": "VPCIGWB7E252D3" + }, + "vpcId": { + "Ref": "VPCB9E5F0B4" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572": { - "id": "AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572", + "AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB25": { + "id": "AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB25", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB25", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1627,7 +1635,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/PseudoTerminalDefaultTestDeployAssert1B88B826.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/PseudoTerminalDefaultTestDeployAssert1B88B826.assets.json index 68f6e85240587..cdfae847794eb 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/PseudoTerminalDefaultTestDeployAssert1B88B826.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/PseudoTerminalDefaultTestDeployAssert1B88B826.assets.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/aws-ecs-integ-pseudo-terminal.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/aws-ecs-integ-pseudo-terminal.assets.json index b7f8120ab6012..c19e19b99bdbc 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/aws-ecs-integ-pseudo-terminal.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/aws-ecs-integ-pseudo-terminal.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "0026f36201f1946b9a59b3c3b965e5bbadf9b83ade054a9a8b08fa6206497660": { + "1c515f480ad77e878b3876a8c8bdb0d02a569ab14fc01751d330378dd204a54c": { "source": { "path": "aws-ecs-integ-pseudo-terminal.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "0026f36201f1946b9a59b3c3b965e5bbadf9b83ade054a9a8b08fa6206497660.json", + "objectKey": "1c515f480ad77e878b3876a8c8bdb0d02a569ab14fc01751d330378dd204a54c.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/aws-ecs-integ-pseudo-terminal.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/aws-ecs-integ-pseudo-terminal.template.json index 2716e688d9d92..256410c9d35bd 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/aws-ecs-integ-pseudo-terminal.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/aws-ecs-integ-pseudo-terminal.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-pseudo-terminal/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-pseudo-terminal/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-pseudo-terminal/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-pseudo-terminal/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ-pseudo-terminal/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-pseudo-terminal/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ-pseudo-terminal/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-pseudo-terminal/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -589,8 +589,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic8C590529A250292C": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook3BB9B6DE44BF8137": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/integ.json index 6226f2812fa4b..b711bff02a114 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "PseudoTerminal/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/manifest.json index 3f4d3757bd404..ab655e211f000 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-pseudo-terminal.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-pseudo-terminal.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}/0026f36201f1946b9a59b3c3b965e5bbadf9b83ade054a9a8b08fa6206497660.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/1c515f480ad77e878b3876a8c8bdb0d02a569ab14fc01751d330378dd204a54c.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic8C590529": [ + "/aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook3BB9B6DE": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic8C590529A250292C" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook3BB9B6DE44BF8137" } ], - "/aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -309,10 +310,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic8C590529A250292C": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic8C590529A250292C", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] @@ -334,6 +353,7 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "PseudoTerminalDefaultTestDeployAssert1B88B826.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}", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/tree.json index c5eae9c0a1c90..0a7ff46a1791f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.pseudo-terminal.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-pseudo-terminal/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-pseudo-terminal/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-pseudo-terminal/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-pseudo-terminal/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ-pseudo-terminal/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-pseudo-terminal/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ-pseudo-terminal/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-pseudo-terminal/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic8C590529": { - "id": "AllowInvoke:awsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic8C590529", - "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic8C590529", + "AllowInvoke:awsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook3BB9B6DE": { + "id": "AllowInvoke:awsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook3BB9B6DE", + "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegpseudoterminalEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook3BB9B6DE", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-pseudo-terminal/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1515,7 +1523,15 @@ "image": "amazon/amazon-ecs-sample", "memory": 256, "name": "web", - "pseudoTerminal": true + "pseudoTerminal": true, + "environment": [ + { + "name": "AWS_REGION", + "value": { + "Ref": "AWS::Region" + } + } + ] } ], "family": "awsecsintegpseudoterminalTaskDefA7C50734", @@ -1681,7 +1697,7 @@ "path": "PseudoTerminal/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "DeployAssert": { @@ -1727,7 +1743,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/aws-ecs-integ-ecs.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/aws-ecs-integ-ecs.assets.json index a9f0d41d691f4..1c2b06795dfa6 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/aws-ecs-integ-ecs.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/aws-ecs-integ-ecs.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "c73d5aba1c7b414dfadb28926ba8e16d5d691eb8862a4a00af9b0d8ecd3e38b9": { + "a47d740860e01f08b1a369d3ae9849898b2e7cc32444d20f46ddb9d2d2c7faff": { "source": { "path": "aws-ecs-integ-ecs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "c73d5aba1c7b414dfadb28926ba8e16d5d691eb8862a4a00af9b0d8ecd3e38b9.json", + "objectKey": "a47d740860e01f08b1a369d3ae9849898b2e7cc32444d20f46ddb9d2d2c7faff.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/aws-ecs-integ-ecs.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/aws-ecs-integ-ecs.template.json index f6431ca60bcb3..53d3a1b792d84 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/aws-ecs-integ-ecs.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/aws-ecs-integ-ecs.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -589,8 +589,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/integ.json index 3e708df29b3ea..f2ebb4c855b4e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.sd-awsvpc-nw": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/manifest.json index f96ee2676ac93..774f6d1eece68 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-ecs.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-ecs.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}/c73d5aba1c7b414dfadb28926ba8e16d5d691eb8862a4a00af9b0d8ecd3e38b9.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/a47d740860e01f08b1a369d3ae9849898b2e7cc32444d20f46ddb9d2d2c7faff.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -321,10 +322,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/tree.json index 2d80a69a28b11..2dedb40fd0d17 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-awsvpc-nw.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": { - "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", + "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": { + "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1548,6 +1556,14 @@ "hostPort": 80, "protocol": "tcp" } + ], + "environment": [ + { + "name": "AWS_REGION", + "value": { + "Ref": "AWS::Region" + } + } ] } ], @@ -1764,7 +1780,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/aws-ecs-integ-ecs.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/aws-ecs-integ-ecs.assets.json index f9db1a6a781db..ed56e8638d1c9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/aws-ecs-integ-ecs.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/aws-ecs-integ-ecs.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "481dd38891149544023fa73b17226d86e546c863dcdc9ff8c43b568d761e8e89": { + "5b399643720a33320438d8add638dc8cd0a3450c0f6d8d006e38145950ac99e0": { "source": { "path": "aws-ecs-integ-ecs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "481dd38891149544023fa73b17226d86e546c863dcdc9ff8c43b568d761e8e89.json", + "objectKey": "5b399643720a33320438d8add638dc8cd0a3450c0f6d8d006e38145950ac99e0.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/aws-ecs-integ-ecs.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/aws-ecs-integ-ecs.template.json index 1bd87cdb2dde2..d0a18654113b2 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/aws-ecs-integ-ecs.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/aws-ecs-integ-ecs.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -589,8 +589,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/integ.json index 335f6cc4fd0a2..6cef0741641b7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.sd-bridge-nw": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/manifest.json index 78b795c055f2e..65ff2a415a327 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-ecs.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-ecs.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}/481dd38891149544023fa73b17226d86e546c863dcdc9ff8c43b568d761e8e89.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5b399643720a33320438d8add638dc8cd0a3450c0f6d8d006e38145950ac99e0.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -315,10 +316,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/tree.json index 41081e34709d7..aa745fefbbd07 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.sd-bridge-nw.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": { - "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", + "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": { + "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1711,7 +1719,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/aws-ecs-integ-spot.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/aws-ecs-integ-spot.assets.json index 29e8243781f33..50ee0acaf254c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/aws-ecs-integ-spot.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/aws-ecs-integ-spot.assets.json @@ -1,7 +1,7 @@ { - "version": "34.0.0", + "version": "36.0.0", "files": { - "44926d05cbee0f90f190349229e489e2618e153e620668d9fe68f22416d3c64f": { + "f445b17f6e979ca9d6ec4f9134d101477bdc66063c2d37ace5d075009f1567b6": { "source": { "path": "aws-ecs-integ-spot.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "44926d05cbee0f90f190349229e489e2618e153e620668d9fe68f22416d3c64f.json", + "objectKey": "f445b17f6e979ca9d6ec4f9134d101477bdc66063c2d37ace5d075009f1567b6.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/aws-ecs-integ-spot.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/aws-ecs-integ-spot.template.json index a2a6a545cdcba..f0de973f1cd88 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/aws-ecs-integ-spot.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/aws-ecs-integ-spot.template.json @@ -792,7 +792,7 @@ "EcsClusterasgSpotDrainECSHookFunctionServiceRole8EEDDFE0" ] }, - "EcsClusterasgSpotDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopic92E2845E8BD3FE4E": { + "EcsClusterasgSpotDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHook91FAF0AE1A000B73": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -804,11 +804,11 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" } } }, - "EcsClusterasgSpotDrainECSHookFunctionTopic9648CAD4": { + "EcsClusterasgSpotDrainECSHookFunctionTopicLifecycleHookDrainHook7836B691": { "Type": "AWS::SNS::Subscription", "Properties": { "Endpoint": { @@ -819,11 +819,11 @@ }, "Protocol": "lambda", "TopicArn": { - "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" } } }, - "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83": { + "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -866,7 +866,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" } } ], @@ -890,7 +890,7 @@ "HeartbeatTimeout": 300, "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" }, "RoleARN": { "Fn::GetAtt": [ @@ -1296,7 +1296,7 @@ "EcsClusterasgOdDrainECSHookFunctionServiceRoleFC088D55" ] }, - "EcsClusterasgOdDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicB293D7D8B41B2D12": { + "EcsClusterasgOdDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHook8D5CD9E5659E5F0E": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -1308,11 +1308,11 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" } } }, - "EcsClusterasgOdDrainECSHookFunctionTopicE6BE4000": { + "EcsClusterasgOdDrainECSHookFunctionTopicLifecycleHookDrainHook1F95CAE2": { "Type": "AWS::SNS::Subscription", "Properties": { "Endpoint": { @@ -1323,11 +1323,11 @@ }, "Protocol": "lambda", "TopicArn": { - "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" } } }, - "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202": { + "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -1370,7 +1370,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" } } ], @@ -1394,7 +1394,7 @@ "HeartbeatTimeout": 300, "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/cdk.out index 2313ab5436501..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"34.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/integ.json index 5e30322c74d2d..f4b1357af6cf4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "testCases": { "integ.spot-drain": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/manifest.json index 289caf86d228a..b6d021a0a693d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-spot.assets": { "type": "cdk:asset-manifest", @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/44926d05cbee0f90f190349229e489e2618e153e620668d9fe68f22416d3c64f.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/f445b17f6e979ca9d6ec4f9134d101477bdc66063c2d37ace5d075009f1567b6.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -238,22 +238,22 @@ "data": "EcsClusterasgSpotDrainECSHookFunction969F1553" } ], - "/aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/AllowInvoke:awsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopic92E2845E": [ + "/aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/AllowInvoke:awsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHook91FAF0AE": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterasgSpotDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopic92E2845E8BD3FE4E" + "data": "EcsClusterasgSpotDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHook91FAF0AE1A000B73" } ], - "/aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterasgSpotDrainECSHookFunctionTopic9648CAD4" + "data": "EcsClusterasgSpotDrainECSHookFunctionTopicLifecycleHookDrainHook7836B691" } ], - "/aws-ecs-integ-spot/EcsCluster/asgSpot/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-spot/EcsCluster/asgSpot/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "data": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" } ], "/aws-ecs-integ-spot/EcsCluster/asgSpot/LifecycleHookDrainHook/Role/Resource": [ @@ -334,22 +334,22 @@ "data": "EcsClusterasgOdDrainECSHookFunction962490E0" } ], - "/aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/AllowInvoke:awsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicB293D7D8": [ + "/aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/AllowInvoke:awsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHook8D5CD9E5": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterasgOdDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicB293D7D8B41B2D12" + "data": "EcsClusterasgOdDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHook8D5CD9E5659E5F0E" } ], - "/aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterasgOdDrainECSHookFunctionTopicE6BE4000" + "data": "EcsClusterasgOdDrainECSHookFunctionTopicLifecycleHookDrainHook1F95CAE2" } ], - "/aws-ecs-integ-spot/EcsCluster/asgOd/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-spot/EcsCluster/asgOd/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "data": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" } ], "/aws-ecs-integ-spot/EcsCluster/asgOd/LifecycleHookDrainHook/Role/Resource": [ @@ -405,6 +405,60 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "EcsClusterasgSpotDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopic92E2845E8BD3FE4E": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterasgSpotDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopic92E2845E8BD3FE4E", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterasgSpotDrainECSHookFunctionTopic9648CAD4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterasgSpotDrainECSHookFunctionTopic9648CAD4", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterasgOdDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicB293D7D8B41B2D12": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterasgOdDrainECSHookFunctionAllowInvokeawsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicB293D7D8B41B2D12", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterasgOdDrainECSHookFunctionTopicE6BE4000": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterasgOdDrainECSHookFunctionTopicE6BE4000", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "aws-ecs-integ-spot" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/tree.json index 83bfc092f6773..7388e6f86da90 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.spot-drain.js.snapshot/tree.json @@ -1217,9 +1217,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopic92E2845E": { - "id": "AllowInvoke:awsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopic92E2845E", - "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/AllowInvoke:awsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopic92E2845E", + "AllowInvoke:awsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHook91FAF0AE": { + "id": "AllowInvoke:awsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHook91FAF0AE", + "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/AllowInvoke:awsecsintegspotEcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHook91FAF0AE", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1232,7 +1232,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" } } }, @@ -1241,13 +1241,13 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { @@ -1259,7 +1259,7 @@ }, "protocol": "lambda", "topicArn": { - "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" } } }, @@ -1283,20 +1283,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-spot/EcsCluster/asgSpot/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1378,7 +1378,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" } } ], @@ -1422,7 +1422,7 @@ "heartbeatTimeout": 300, "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopic6212EC83" + "Ref": "EcsClusterasgSpotLifecycleHookDrainHookTopicLifecycleHookDrainHookF0C9E866" }, "roleArn": { "Fn::GetAtt": [ @@ -1993,9 +1993,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicB293D7D8": { - "id": "AllowInvoke:awsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicB293D7D8", - "path": "aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/AllowInvoke:awsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicB293D7D8", + "AllowInvoke:awsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHook8D5CD9E5": { + "id": "AllowInvoke:awsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHook8D5CD9E5", + "path": "aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/AllowInvoke:awsecsintegspotEcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHook8D5CD9E5", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -2008,7 +2008,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" } } }, @@ -2017,13 +2017,13 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-spot/EcsCluster/asgOd/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { @@ -2035,7 +2035,7 @@ }, "protocol": "lambda", "topicArn": { - "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" } } }, @@ -2059,20 +2059,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-spot/EcsCluster/asgOd/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-spot/EcsCluster/asgOd/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-spot/EcsCluster/asgOd/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-spot/EcsCluster/asgOd/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-spot/EcsCluster/asgOd/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -2154,7 +2154,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" } } ], @@ -2198,7 +2198,7 @@ "heartbeatTimeout": 300, "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopic673CE202" + "Ref": "EcsClusterasgOdLifecycleHookDrainHookTopicLifecycleHookDrainHookAB085AA1" }, "roleArn": { "Fn::GetAtt": [ @@ -2415,7 +2415,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/SwapParametersTestDefaultTestDeployAssert4CDF4940.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/SwapParametersTestDefaultTestDeployAssert4CDF4940.assets.json index ecd857d18b1e1..e0b00f9e350d8 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/SwapParametersTestDefaultTestDeployAssert4CDF4940.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/SwapParametersTestDefaultTestDeployAssert4CDF4940.assets.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/aws-ecs-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/aws-ecs-integ.assets.json index 9fa68ee8742f1..807a5df867096 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/aws-ecs-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/aws-ecs-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "3ff2bd8a4a5be837d5bb8e7a17fdfae42b531493af3777cf4eb0459fe3587b2c": { + "52292687ea741cc1186a716320e943fb213cb32d9deabe1774796364ba3d9983": { "source": { "path": "aws-ecs-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "3ff2bd8a4a5be837d5bb8e7a17fdfae42b531493af3777cf4eb0459fe3587b2c.json", + "objectKey": "52292687ea741cc1186a716320e943fb213cb32d9deabe1774796364ba3d9983.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/aws-ecs-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/aws-ecs-integ.template.json index 5cc54d558f6c2..82b887a8d74be 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/aws-ecs-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/aws-ecs-integ.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPublicSubnet2Subnet691E08A3": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTable94F7E489": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet2RouteTableAssociationDD5762D8": { @@ -183,12 +183,12 @@ "VpcPublicSubnet2DefaultRoute97F91067": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } }, "DependsOn": [ @@ -210,15 +210,15 @@ "VpcPublicSubnet2NATGateway9182C01D": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "Tags": [ { "Key": "Name", @@ -234,9 +234,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -260,21 +257,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -291,21 +291,18 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, "VpcPrivateSubnet2Subnet3788AAA1": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -329,21 +326,24 @@ "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableA678073B": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { @@ -360,12 +360,12 @@ "VpcPrivateSubnet2DefaultRoute060D2087": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -383,11 +383,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -589,8 +589,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/cdk.out index 7df7694e7a5a5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/integ.json index d366f50c6a897..9ab307c43388b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "SwapParametersTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/manifest.json index 94a7c95254cdf..9814afa5af749 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ.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}/3ff2bd8a4a5be837d5bb8e7a17fdfae42b531493af3777cf4eb0459fe3587b2c.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/52292687ea741cc1186a716320e943fb213cb32d9deabe1774796364ba3d9983.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B19CCF2DB" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -309,10 +310,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925AFDCBEE50", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] @@ -334,6 +353,7 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "SwapParametersTestDefaultTestDeployAssert4CDF4940.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}", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/tree.json index aa31c9f8e2888..72576debc4997 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.swap-parameters.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet2RouteTable94F7E489" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" } } }, @@ -341,15 +341,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet2Subnet691E08A3" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet2EIP3C605A87", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, "tags": [ { "key": "Name", @@ -379,9 +379,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -405,7 +402,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -427,15 +427,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -468,12 +468,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -498,9 +498,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -524,7 +521,10 @@ "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -546,15 +546,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -587,12 +587,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet2RouteTableA678073B" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet2NATGateway9182C01D" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" } } }, @@ -632,11 +632,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A": { - "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic7A89925A", + "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B": { + "id": "AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook5102437B", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1693,7 +1701,7 @@ "path": "SwapParametersTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "DeployAssert": { @@ -1739,7 +1747,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/__entrypoint__.js b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/__entrypoint__.js deleted file mode 100644 index c83ecebaaadac..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/__entrypoint__.js +++ /dev/null @@ -1,147 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.withRetries = exports.handler = exports.external = void 0; -const https = require("https"); -const url = require("url"); -// for unit tests -exports.external = { - sendHttpRequest: defaultSendHttpRequest, - log: defaultLog, - includeStackTraces: true, - userHandlerIndex: './index', -}; -const CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; -const MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; -async function handler(event, context) { - const sanitizedEvent = { ...event, ResponseURL: '...' }; - exports.external.log(JSON.stringify(sanitizedEvent, undefined, 2)); - // ignore DELETE event when the physical resource ID is the marker that - // indicates that this DELETE is a subsequent DELETE to a failed CREATE - // operation. - if (event.RequestType === 'Delete' && event.PhysicalResourceId === CREATE_FAILED_PHYSICAL_ID_MARKER) { - exports.external.log('ignoring DELETE event caused by a failed CREATE event'); - await submitResponse('SUCCESS', event); - return; - } - try { - // invoke the user handler. this is intentionally inside the try-catch to - // ensure that if there is an error it's reported as a failure to - // cloudformation (otherwise cfn waits). - // eslint-disable-next-line @typescript-eslint/no-require-imports - const userHandler = require(exports.external.userHandlerIndex).handler; - const result = await userHandler(sanitizedEvent, context); - // validate user response and create the combined event - const responseEvent = renderResponse(event, result); - // submit to cfn as success - await submitResponse('SUCCESS', responseEvent); - } - catch (e) { - const resp = { - ...event, - Reason: exports.external.includeStackTraces ? e.stack : e.message, - }; - if (!resp.PhysicalResourceId) { - // special case: if CREATE fails, which usually implies, we usually don't - // have a physical resource id. in this case, the subsequent DELETE - // operation does not have any meaning, and will likely fail as well. to - // address this, we use a marker so the provider framework can simply - // ignore the subsequent DELETE. - if (event.RequestType === 'Create') { - exports.external.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); - resp.PhysicalResourceId = CREATE_FAILED_PHYSICAL_ID_MARKER; - } - else { - // otherwise, if PhysicalResourceId is not specified, something is - // terribly wrong because all other events should have an ID. - exports.external.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(event)}`); - } - } - // this is an actual error, fail the activity altogether and exist. - await submitResponse('FAILED', resp); - } -} -exports.handler = handler; -function renderResponse(cfnRequest, handlerResponse = {}) { - // if physical ID is not returned, we have some defaults for you based - // on the request type. - const physicalResourceId = handlerResponse.PhysicalResourceId ?? cfnRequest.PhysicalResourceId ?? cfnRequest.RequestId; - // if we are in DELETE and physical ID was changed, it's an error. - if (cfnRequest.RequestType === 'Delete' && physicalResourceId !== cfnRequest.PhysicalResourceId) { - throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${handlerResponse.PhysicalResourceId}" during deletion`); - } - // merge request event and result event (result prevails). - return { - ...cfnRequest, - ...handlerResponse, - PhysicalResourceId: physicalResourceId, - }; -} -async function submitResponse(status, event) { - const json = { - Status: status, - Reason: event.Reason ?? status, - StackId: event.StackId, - RequestId: event.RequestId, - PhysicalResourceId: event.PhysicalResourceId || MISSING_PHYSICAL_ID_MARKER, - LogicalResourceId: event.LogicalResourceId, - NoEcho: event.NoEcho, - Data: event.Data, - }; - exports.external.log('submit response to cloudformation', json); - const responseBody = JSON.stringify(json); - const parsedUrl = url.parse(event.ResponseURL); - const req = { - hostname: parsedUrl.hostname, - path: parsedUrl.path, - method: 'PUT', - headers: { - 'content-type': '', - 'content-length': Buffer.byteLength(responseBody, 'utf8'), - }, - }; - const retryOptions = { - attempts: 5, - sleep: 1000, - }; - await withRetries(retryOptions, exports.external.sendHttpRequest)(req, responseBody); -} -async function defaultSendHttpRequest(options, responseBody) { - return new Promise((resolve, reject) => { - try { - const request = https.request(options, _ => resolve()); - request.on('error', reject); - request.write(responseBody); - request.end(); - } - catch (e) { - reject(e); - } - }); -} -function defaultLog(fmt, ...params) { - // eslint-disable-next-line no-console - console.log(fmt, ...params); -} -function withRetries(options, fn) { - return async (...xs) => { - let attempts = options.attempts; - let ms = options.sleep; - while (true) { - try { - return await fn(...xs); - } - catch (e) { - if (attempts-- <= 0) { - throw e; - } - await sleep(Math.floor(Math.random() * ms)); - ms *= 2; - } - } - }; -} -exports.withRetries = withRetries; -async function sleep(ms) { - return new Promise((ok) => setTimeout(ok, ms)); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWpzLWVudHJ5cG9pbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJub2RlanMtZW50cnlwb2ludC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBRTNCLGlCQUFpQjtBQUNKLFFBQUEsUUFBUSxHQUFHO0lBQ3RCLGVBQWUsRUFBRSxzQkFBc0I7SUFDdkMsR0FBRyxFQUFFLFVBQVU7SUFDZixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGdCQUFnQixFQUFFLFNBQVM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sZ0NBQWdDLEdBQUcsd0RBQXdELENBQUM7QUFDbEcsTUFBTSwwQkFBMEIsR0FBRyw4REFBOEQsQ0FBQztBQVczRixLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQWtELEVBQUUsT0FBMEI7SUFDMUcsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDeEQsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFM0QsdUVBQXVFO0lBQ3ZFLHVFQUF1RTtJQUN2RSxhQUFhO0lBQ2IsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssZ0NBQWdDLEVBQUU7UUFDbkcsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUN0RSxNQUFNLGNBQWMsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkMsT0FBTztLQUNSO0lBRUQsSUFBSTtRQUNGLHlFQUF5RTtRQUN6RSxpRUFBaUU7UUFDakUsd0NBQXdDO1FBQ3hDLGlFQUFpRTtRQUNqRSxNQUFNLFdBQVcsR0FBWSxPQUFPLENBQUMsZ0JBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxNQUFNLE1BQU0sR0FBRyxNQUFNLFdBQVcsQ0FBQyxjQUFjLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFMUQsdURBQXVEO1FBQ3ZELE1BQU0sYUFBYSxHQUFHLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFcEQsMkJBQTJCO1FBQzNCLE1BQU0sY0FBYyxDQUFDLFNBQVMsRUFBRSxhQUFhLENBQUMsQ0FBQztLQUNoRDtJQUFDLE9BQU8sQ0FBTSxFQUFFO1FBQ2YsTUFBTSxJQUFJLEdBQWE7WUFDckIsR0FBRyxLQUFLO1lBQ1IsTUFBTSxFQUFFLGdCQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPO1NBQzFELENBQUM7UUFFRixJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFO1lBQzVCLHlFQUF5RTtZQUN6RSxtRUFBbUU7WUFDbkUsd0VBQXdFO1lBQ3hFLHFFQUFxRTtZQUNyRSxnQ0FBZ0M7WUFDaEMsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtnQkFDbEMsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsNEdBQTRHLENBQUMsQ0FBQztnQkFDM0gsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGdDQUFnQyxDQUFDO2FBQzVEO2lCQUFNO2dCQUNMLGtFQUFrRTtnQkFDbEUsNkRBQTZEO2dCQUM3RCxnQkFBUSxDQUFDLEdBQUcsQ0FBQyw2REFBNkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDcEc7U0FDRjtRQUVELG1FQUFtRTtRQUNuRSxNQUFNLGNBQWMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7S0FDdEM7QUFDSCxDQUFDO0FBbkRELDBCQW1EQztBQUVELFNBQVMsY0FBYyxDQUNyQixVQUF5RixFQUN6RixrQkFBMEMsRUFBRztJQUU3QyxzRUFBc0U7SUFDdEUsdUJBQXVCO0lBQ3ZCLE1BQU0sa0JBQWtCLEdBQUcsZUFBZSxDQUFDLGtCQUFrQixJQUFJLFVBQVUsQ0FBQyxrQkFBa0IsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDO0lBRXZILGtFQUFrRTtJQUNsRSxJQUFJLFVBQVUsQ0FBQyxXQUFXLEtBQUssUUFBUSxJQUFJLGtCQUFrQixLQUFLLFVBQVUsQ0FBQyxrQkFBa0IsRUFBRTtRQUMvRixNQUFNLElBQUksS0FBSyxDQUFDLHdEQUF3RCxVQUFVLENBQUMsa0JBQWtCLFNBQVMsZUFBZSxDQUFDLGtCQUFrQixtQkFBbUIsQ0FBQyxDQUFDO0tBQ3RLO0lBRUQsMERBQTBEO0lBQzFELE9BQU87UUFDTCxHQUFHLFVBQVU7UUFDYixHQUFHLGVBQWU7UUFDbEIsa0JBQWtCLEVBQUUsa0JBQWtCO0tBQ3ZDLENBQUM7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLGNBQWMsQ0FBQyxNQUE0QixFQUFFLEtBQWU7SUFDekUsTUFBTSxJQUFJLEdBQW1EO1FBQzNELE1BQU0sRUFBRSxNQUFNO1FBQ2QsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLElBQUksTUFBTTtRQUM5QixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87UUFDdEIsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1FBQzFCLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSwwQkFBMEI7UUFDMUUsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtRQUMxQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO0tBQ2pCLENBQUM7SUFFRixnQkFBUSxDQUFDLEdBQUcsQ0FBQyxtQ0FBbUMsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUV4RCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFDLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQy9DLE1BQU0sR0FBRyxHQUFHO1FBQ1YsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO1FBQzVCLElBQUksRUFBRSxTQUFTLENBQUMsSUFBSTtRQUNwQixNQUFNLEVBQUUsS0FBSztRQUNiLE9BQU8sRUFBRTtZQUNQLGNBQWMsRUFBRSxFQUFFO1lBQ2xCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQztTQUMxRDtLQUNGLENBQUM7SUFFRixNQUFNLFlBQVksR0FBRztRQUNuQixRQUFRLEVBQUUsQ0FBQztRQUNYLEtBQUssRUFBRSxJQUFJO0tBQ1osQ0FBQztJQUNGLE1BQU0sV0FBVyxDQUFDLFlBQVksRUFBRSxnQkFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsQ0FBQztBQUMvRSxDQUFDO0FBRUQsS0FBSyxVQUFVLHNCQUFzQixDQUFDLE9BQTZCLEVBQUUsWUFBb0I7SUFDdkYsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNyQyxJQUFJO1lBQ0YsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDNUIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1NBQ2Y7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNYO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsR0FBVyxFQUFFLEdBQUcsTUFBYTtJQUMvQyxzQ0FBc0M7SUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQztBQUM5QixDQUFDO0FBU0QsU0FBZ0IsV0FBVyxDQUEwQixPQUFxQixFQUFFLEVBQTRCO0lBQ3RHLE9BQU8sS0FBSyxFQUFFLEdBQUcsRUFBSyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLE9BQU8sSUFBSSxFQUFFO1lBQ1gsSUFBSTtnQkFDRixPQUFPLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDeEI7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRTtvQkFDbkIsTUFBTSxDQUFDLENBQUM7aUJBQ1Q7Z0JBQ0QsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDNUMsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNUO1NBQ0Y7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDO0FBaEJELGtDQWdCQztBQUVELEtBQUssVUFBVSxLQUFLLENBQUMsRUFBVTtJQUM3QixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDakQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG4vLyBmb3IgdW5pdCB0ZXN0c1xuZXhwb3J0IGNvbnN0IGV4dGVybmFsID0ge1xuICBzZW5kSHR0cFJlcXVlc3Q6IGRlZmF1bHRTZW5kSHR0cFJlcXVlc3QsXG4gIGxvZzogZGVmYXVsdExvZyxcbiAgaW5jbHVkZVN0YWNrVHJhY2VzOiB0cnVlLFxuICB1c2VySGFuZGxlckluZGV4OiAnLi9pbmRleCcsXG59O1xuXG5jb25zdCBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUiA9ICdBV1NDREs6OkN1c3RvbVJlc291cmNlUHJvdmlkZXJGcmFtZXdvcms6OkNSRUFURV9GQUlMRUQnO1xuY29uc3QgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpNSVNTSU5HX1BIWVNJQ0FMX0lEJztcblxuZXhwb3J0IHR5cGUgUmVzcG9uc2UgPSBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgSGFuZGxlclJlc3BvbnNlO1xuZXhwb3J0IHR5cGUgSGFuZGxlciA9IChldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCwgY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpID0+IFByb21pc2U8SGFuZGxlclJlc3BvbnNlIHwgdm9pZD47XG5leHBvcnQgdHlwZSBIYW5kbGVyUmVzcG9uc2UgPSB1bmRlZmluZWQgfCB7XG4gIERhdGE/OiBhbnk7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgUmVhc29uPzogc3RyaW5nO1xuICBOb0VjaG8/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIGNvbnRleHQ6IEFXU0xhbWJkYS5Db250ZXh0KSB7XG4gIGNvbnN0IHNhbml0aXplZEV2ZW50ID0geyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH07XG4gIGV4dGVybmFsLmxvZyhKU09OLnN0cmluZ2lmeShzYW5pdGl6ZWRFdmVudCwgdW5kZWZpbmVkLCAyKSk7XG5cbiAgLy8gaWdub3JlIERFTEVURSBldmVudCB3aGVuIHRoZSBwaHlzaWNhbCByZXNvdXJjZSBJRCBpcyB0aGUgbWFya2VyIHRoYXRcbiAgLy8gaW5kaWNhdGVzIHRoYXQgdGhpcyBERUxFVEUgaXMgYSBzdWJzZXF1ZW50IERFTEVURSB0byBhIGZhaWxlZCBDUkVBVEVcbiAgLy8gb3BlcmF0aW9uLlxuICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9PT0gQ1JFQVRFX0ZBSUxFRF9QSFlTSUNBTF9JRF9NQVJLRVIpIHtcbiAgICBleHRlcm5hbC5sb2coJ2lnbm9yaW5nIERFTEVURSBldmVudCBjYXVzZWQgYnkgYSBmYWlsZWQgQ1JFQVRFIGV2ZW50Jyk7XG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBpbnZva2UgdGhlIHVzZXIgaGFuZGxlci4gdGhpcyBpcyBpbnRlbnRpb25hbGx5IGluc2lkZSB0aGUgdHJ5LWNhdGNoIHRvXG4gICAgLy8gZW5zdXJlIHRoYXQgaWYgdGhlcmUgaXMgYW4gZXJyb3IgaXQncyByZXBvcnRlZCBhcyBhIGZhaWx1cmUgdG9cbiAgICAvLyBjbG91ZGZvcm1hdGlvbiAob3RoZXJ3aXNlIGNmbiB3YWl0cykuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCB1c2VySGFuZGxlcjogSGFuZGxlciA9IHJlcXVpcmUoZXh0ZXJuYWwudXNlckhhbmRsZXJJbmRleCkuaGFuZGxlcjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB1c2VySGFuZGxlcihzYW5pdGl6ZWRFdmVudCwgY29udGV4dCk7XG5cbiAgICAvLyB2YWxpZGF0ZSB1c2VyIHJlc3BvbnNlIGFuZCBjcmVhdGUgdGhlIGNvbWJpbmVkIGV2ZW50XG4gICAgY29uc3QgcmVzcG9uc2VFdmVudCA9IHJlbmRlclJlc3BvbnNlKGV2ZW50LCByZXN1bHQpO1xuXG4gICAgLy8gc3VibWl0IHRvIGNmbiBhcyBzdWNjZXNzXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCByZXNwb25zZUV2ZW50KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgY29uc3QgcmVzcDogUmVzcG9uc2UgPSB7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIFJlYXNvbjogZXh0ZXJuYWwuaW5jbHVkZVN0YWNrVHJhY2VzID8gZS5zdGFjayA6IGUubWVzc2FnZSxcbiAgICB9O1xuXG4gICAgaWYgKCFyZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCkge1xuICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgLy8gaGF2ZSBhIHBoeXNpY2FsIHJlc291cmNlIGlkLiBpbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXF1ZW50IERFTEVURVxuICAgICAgLy8gb3BlcmF0aW9uIGRvZXMgbm90IGhhdmUgYW55IG1lYW5pbmcsIGFuZCB3aWxsIGxpa2VseSBmYWlsIGFzIHdlbGwuIHRvXG4gICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgIC8vIGlnbm9yZSB0aGUgc3Vic2VxdWVudCBERUxFVEUuXG4gICAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnKSB7XG4gICAgICAgIGV4dGVybmFsLmxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICByZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gb3RoZXJ3aXNlLCBpZiBQaHlzaWNhbFJlc291cmNlSWQgaXMgbm90IHNwZWNpZmllZCwgc29tZXRoaW5nIGlzXG4gICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgZXh0ZXJuYWwubG9nKGBFUlJPUjogTWFsZm9ybWVkIGV2ZW50LiBcIlBoeXNpY2FsUmVzb3VyY2VJZFwiIGlzIHJlcXVpcmVkOiAke0pTT04uc3RyaW5naWZ5KGV2ZW50KX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyB0aGlzIGlzIGFuIGFjdHVhbCBlcnJvciwgZmFpbCB0aGUgYWN0aXZpdHkgYWx0b2dldGhlciBhbmQgZXhpc3QuXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ0ZBSUxFRCcsIHJlc3ApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlbmRlclJlc3BvbnNlKFxuICBjZm5SZXF1ZXN0OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgeyBQaHlzaWNhbFJlc291cmNlSWQ/OiBzdHJpbmcgfSxcbiAgaGFuZGxlclJlc3BvbnNlOiB2b2lkIHwgSGFuZGxlclJlc3BvbnNlID0geyB9KTogUmVzcG9uc2Uge1xuXG4gIC8vIGlmIHBoeXNpY2FsIElEIGlzIG5vdCByZXR1cm5lZCwgd2UgaGF2ZSBzb21lIGRlZmF1bHRzIGZvciB5b3UgYmFzZWRcbiAgLy8gb24gdGhlIHJlcXVlc3QgdHlwZS5cbiAgY29uc3QgcGh5c2ljYWxSZXNvdXJjZUlkID0gaGFuZGxlclJlc3BvbnNlLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlJlcXVlc3RJZDtcblxuICAvLyBpZiB3ZSBhcmUgaW4gREVMRVRFIGFuZCBwaHlzaWNhbCBJRCB3YXMgY2hhbmdlZCwgaXQncyBhbiBlcnJvci5cbiAgaWYgKGNmblJlcXVlc3QuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIHBoeXNpY2FsUmVzb3VyY2VJZCAhPT0gY2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERFTEVURTogY2Fubm90IGNoYW5nZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSBcIiR7Y2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWR9XCIgdG8gXCIke2hhbmRsZXJSZXNwb25zZS5QaHlzaWNhbFJlc291cmNlSWR9XCIgZHVyaW5nIGRlbGV0aW9uYCk7XG4gIH1cblxuICAvLyBtZXJnZSByZXF1ZXN0IGV2ZW50IGFuZCByZXN1bHQgZXZlbnQgKHJlc3VsdCBwcmV2YWlscykuXG4gIHJldHVybiB7XG4gICAgLi4uY2ZuUmVxdWVzdCxcbiAgICAuLi5oYW5kbGVyUmVzcG9uc2UsXG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN1Ym1pdFJlc3BvbnNlKHN0YXR1czogJ1NVQ0NFU1MnIHwgJ0ZBSUxFRCcsIGV2ZW50OiBSZXNwb25zZSkge1xuICBjb25zdCBqc29uOiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlID0ge1xuICAgIFN0YXR1czogc3RhdHVzLFxuICAgIFJlYXNvbjogZXZlbnQuUmVhc29uID8/IHN0YXR1cyxcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkIHx8IE1JU1NJTkdfUEhZU0lDQUxfSURfTUFSS0VSLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBOb0VjaG86IGV2ZW50Lk5vRWNobyxcbiAgICBEYXRhOiBldmVudC5EYXRhLFxuICB9O1xuXG4gIGV4dGVybmFsLmxvZygnc3VibWl0IHJlc3BvbnNlIHRvIGNsb3VkZm9ybWF0aW9uJywganNvbik7XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoanNvbik7XG4gIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShldmVudC5SZXNwb25zZVVSTCk7XG4gIGNvbnN0IHJlcSA9IHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogQnVmZmVyLmJ5dGVMZW5ndGgocmVzcG9uc2VCb2R5LCAndXRmOCcpLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3QgcmV0cnlPcHRpb25zID0ge1xuICAgIGF0dGVtcHRzOiA1LFxuICAgIHNsZWVwOiAxMDAwLFxuICB9O1xuICBhd2FpdCB3aXRoUmV0cmllcyhyZXRyeU9wdGlvbnMsIGV4dGVybmFsLnNlbmRIdHRwUmVxdWVzdCkocmVxLCByZXNwb25zZUJvZHkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0U2VuZEh0dHBSZXF1ZXN0KG9wdGlvbnM6IGh0dHBzLlJlcXVlc3RPcHRpb25zLCByZXNwb25zZUJvZHk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCBfID0+IHJlc29sdmUoKSk7XG4gICAgICByZXF1ZXN0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICByZXF1ZXN0LndyaXRlKHJlc3BvbnNlQm9keSk7XG4gICAgICByZXF1ZXN0LmVuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWZhdWx0TG9nKGZtdDogc3RyaW5nLCAuLi5wYXJhbXM6IGFueVtdKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gIGNvbnNvbGUubG9nKGZtdCwgLi4ucGFyYW1zKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXRyeU9wdGlvbnMge1xuICAvKiogSG93IG1hbnkgcmV0cmllcyAod2lsbCBhdCBsZWFzdCB0cnkgb25jZSkgKi9cbiAgcmVhZG9ubHkgYXR0ZW1wdHM6IG51bWJlcjtcbiAgLyoqIFNsZWVwIGJhc2UsIGluIG1zICovXG4gIHJlYWRvbmx5IHNsZWVwOiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB3aXRoUmV0cmllczxBIGV4dGVuZHMgQXJyYXk8YW55PiwgQj4ob3B0aW9uczogUmV0cnlPcHRpb25zLCBmbjogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+KTogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+IHtcbiAgcmV0dXJuIGFzeW5jICguLi54czogQSkgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IG9wdGlvbnMuYXR0ZW1wdHM7XG4gICAgbGV0IG1zID0gb3B0aW9ucy5zbGVlcDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGZuKC4uLnhzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGF0dGVtcHRzLS0gPD0gMCkge1xuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgc2xlZXAoTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbXMpKTtcbiAgICAgICAgbXMgKj0gMjtcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChvaykgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/index.js deleted file mode 100644 index 8cbc0ea437b76..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837/index.js +++ /dev/null @@ -1,81 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.handler = void 0; -/* eslint-disable-next-line import/no-extraneous-dependencies */ -const sdk = require("@aws-sdk/client-ec2"); -const ec2 = new sdk.EC2({}); -/** - * The default security group ingress rule. This can be used to both revoke and authorize the rules - */ -function ingressRuleParams(groupId, account) { - return { - GroupId: groupId, - IpPermissions: [{ - UserIdGroupPairs: [{ - GroupId: groupId, - UserId: account, - }], - IpProtocol: '-1', - }], - }; -} -/** - * The default security group egress rule. This can be used to both revoke and authorize the rules - */ -function egressRuleParams(groupId) { - return { - GroupId: groupId, - IpPermissions: [{ - IpRanges: [{ - CidrIp: '0.0.0.0/0', - }], - IpProtocol: '-1', - }], - }; -} -/** - * Process a custom resource request to restrict the default security group - * ingress & egress rules. - * - * When someone turns off the property then this custom resource will be deleted in which - * case we should add back the rules that were removed. - */ -async function handler(event) { - const securityGroupId = event.ResourceProperties.DefaultSecurityGroupId; - const account = event.ResourceProperties.Account; - switch (event.RequestType) { - case 'Create': - return revokeRules(securityGroupId, account); - case 'Update': - return onUpdate(event); - case 'Delete': - return authorizeRules(securityGroupId, account); - } -} -exports.handler = handler; -async function onUpdate(event) { - const oldSg = event.OldResourceProperties.DefaultSecurityGroupId; - const newSg = event.ResourceProperties.DefaultSecurityGroupId; - if (oldSg !== newSg) { - await authorizeRules(oldSg, event.ResourceProperties.Account); - await revokeRules(newSg, event.ResourceProperties.Account); - } - return; -} -/** - * Revoke both ingress and egress rules - */ -async function revokeRules(groupId, account) { - await ec2.revokeSecurityGroupEgress(egressRuleParams(groupId)); - await ec2.revokeSecurityGroupIngress(ingressRuleParams(groupId, account)); - return; -} -/** - * Authorize both ingress and egress rules - */ -async function authorizeRules(groupId, account) { - await ec2.authorizeSecurityGroupIngress(ingressRuleParams(groupId, account)); - await ec2.authorizeSecurityGroupEgress(egressRuleParams(groupId)); - return; -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxnRUFBZ0U7QUFDaEUsMkNBQTJDO0FBRTNDLE1BQU0sR0FBRyxHQUFHLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUU1Qjs7R0FFRztBQUNILFNBQVMsaUJBQWlCLENBQUMsT0FBZSxFQUFFLE9BQWU7SUFHekQsT0FBTztRQUNMLE9BQU8sRUFBRSxPQUFPO1FBQ2hCLGFBQWEsRUFBRSxDQUFDO2dCQUNkLGdCQUFnQixFQUFFLENBQUM7d0JBQ2pCLE9BQU8sRUFBRSxPQUFPO3dCQUNoQixNQUFNLEVBQUUsT0FBTztxQkFDaEIsQ0FBQztnQkFDRixVQUFVLEVBQUUsSUFBSTthQUNqQixDQUFDO0tBQ0gsQ0FBQztBQUNKLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsT0FBZTtJQUN2QyxPQUFPO1FBQ0wsT0FBTyxFQUFFLE9BQU87UUFDaEIsYUFBYSxFQUFFLENBQUM7Z0JBQ2QsUUFBUSxFQUFFLENBQUM7d0JBQ1QsTUFBTSxFQUFFLFdBQVc7cUJBQ3BCLENBQUM7Z0JBQ0YsVUFBVSxFQUFFLElBQUk7YUFDakIsQ0FBQztLQUNILENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0ksS0FBSyxVQUFVLE9BQU8sQ0FBQyxLQUFrRDtJQUM5RSxNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUMsa0JBQWtCLENBQUMsc0JBQXNCLENBQUM7SUFDeEUsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQztJQUNqRCxRQUFRLEtBQUssQ0FBQyxXQUFXLEVBQUU7UUFDekIsS0FBSyxRQUFRO1lBQ1gsT0FBTyxXQUFXLENBQUMsZUFBZSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQy9DLEtBQUssUUFBUTtZQUNYLE9BQU8sUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3pCLEtBQUssUUFBUTtZQUNYLE9BQU8sY0FBYyxDQUFDLGVBQWUsRUFBRSxPQUFPLENBQUMsQ0FBQztLQUNuRDtBQUNILENBQUM7QUFYRCwwQkFXQztBQUNELEtBQUssVUFBVSxRQUFRLENBQUMsS0FBd0Q7SUFDOUUsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLHFCQUFxQixDQUFDLHNCQUFzQixDQUFDO0lBQ2pFLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxzQkFBc0IsQ0FBQztJQUM5RCxJQUFJLEtBQUssS0FBSyxLQUFLLEVBQUU7UUFDbkIsTUFBTSxjQUFjLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5RCxNQUFNLFdBQVcsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0tBQzVEO0lBQ0QsT0FBTztBQUNULENBQUM7QUFFRDs7R0FFRztBQUNILEtBQUssVUFBVSxXQUFXLENBQUMsT0FBZSxFQUFFLE9BQWU7SUFDekQsTUFBTSxHQUFHLENBQUMseUJBQXlCLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUMvRCxNQUFNLEdBQUcsQ0FBQywwQkFBMEIsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUMxRSxPQUFPO0FBQ1QsQ0FBQztBQUVEOztHQUVHO0FBQ0gsS0FBSyxVQUFVLGNBQWMsQ0FBQyxPQUFlLEVBQUUsT0FBZTtJQUM1RCxNQUFNLEdBQUcsQ0FBQyw2QkFBNkIsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUM3RSxNQUFNLEdBQUcsQ0FBQyw0QkFBNEIsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ2xFLE9BQU87QUFDVCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcyAqL1xuaW1wb3J0ICogYXMgc2RrIGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1lYzInO1xuXG5jb25zdCBlYzIgPSBuZXcgc2RrLkVDMih7fSk7XG5cbi8qKlxuICogVGhlIGRlZmF1bHQgc2VjdXJpdHkgZ3JvdXAgaW5ncmVzcyBydWxlLiBUaGlzIGNhbiBiZSB1c2VkIHRvIGJvdGggcmV2b2tlIGFuZCBhdXRob3JpemUgdGhlIHJ1bGVzXG4gKi9cbmZ1bmN0aW9uIGluZ3Jlc3NSdWxlUGFyYW1zKGdyb3VwSWQ6IHN0cmluZywgYWNjb3VudDogc3RyaW5nKTpcbnNkay5SZXZva2VTZWN1cml0eUdyb3VwSW5ncmVzc0NvbW1hbmRJbnB1dFxufCBzZGsuQXV0aG9yaXplU2VjdXJpdHlHcm91cEluZ3Jlc3NDb21tYW5kSW5wdXQge1xuICByZXR1cm4ge1xuICAgIEdyb3VwSWQ6IGdyb3VwSWQsXG4gICAgSXBQZXJtaXNzaW9uczogW3tcbiAgICAgIFVzZXJJZEdyb3VwUGFpcnM6IFt7XG4gICAgICAgIEdyb3VwSWQ6IGdyb3VwSWQsXG4gICAgICAgIFVzZXJJZDogYWNjb3VudCxcbiAgICAgIH1dLFxuICAgICAgSXBQcm90b2NvbDogJy0xJyxcbiAgICB9XSxcbiAgfTtcbn1cblxuLyoqXG4gKiBUaGUgZGVmYXVsdCBzZWN1cml0eSBncm91cCBlZ3Jlc3MgcnVsZS4gVGhpcyBjYW4gYmUgdXNlZCB0byBib3RoIHJldm9rZSBhbmQgYXV0aG9yaXplIHRoZSBydWxlc1xuICovXG5mdW5jdGlvbiBlZ3Jlc3NSdWxlUGFyYW1zKGdyb3VwSWQ6IHN0cmluZyk6IHNkay5SZXZva2VTZWN1cml0eUdyb3VwRWdyZXNzQ29tbWFuZElucHV0IHwgc2RrLkF1dGhvcml6ZVNlY3VyaXR5R3JvdXBFZ3Jlc3NDb21tYW5kSW5wdXQge1xuICByZXR1cm4ge1xuICAgIEdyb3VwSWQ6IGdyb3VwSWQsXG4gICAgSXBQZXJtaXNzaW9uczogW3tcbiAgICAgIElwUmFuZ2VzOiBbe1xuICAgICAgICBDaWRySXA6ICcwLjAuMC4wLzAnLFxuICAgICAgfV0sXG4gICAgICBJcFByb3RvY29sOiAnLTEnLFxuICAgIH1dLFxuICB9O1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSBjdXN0b20gcmVzb3VyY2UgcmVxdWVzdCB0byByZXN0cmljdCB0aGUgZGVmYXVsdCBzZWN1cml0eSBncm91cFxuICogaW5ncmVzcyAmIGVncmVzcyBydWxlcy5cbiAqXG4gKiBXaGVuIHNvbWVvbmUgdHVybnMgb2ZmIHRoZSBwcm9wZXJ0eSB0aGVuIHRoaXMgY3VzdG9tIHJlc291cmNlIHdpbGwgYmUgZGVsZXRlZCBpbiB3aGljaFxuICogY2FzZSB3ZSBzaG91bGQgYWRkIGJhY2sgdGhlIHJ1bGVzIHRoYXQgd2VyZSByZW1vdmVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlcihldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBzZWN1cml0eUdyb3VwSWQgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuRGVmYXVsdFNlY3VyaXR5R3JvdXBJZDtcbiAgY29uc3QgYWNjb3VudCA9IGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5BY2NvdW50O1xuICBzd2l0Y2ggKGV2ZW50LlJlcXVlc3RUeXBlKSB7XG4gICAgY2FzZSAnQ3JlYXRlJzpcbiAgICAgIHJldHVybiByZXZva2VSdWxlcyhzZWN1cml0eUdyb3VwSWQsIGFjY291bnQpO1xuICAgIGNhc2UgJ1VwZGF0ZSc6XG4gICAgICByZXR1cm4gb25VcGRhdGUoZXZlbnQpO1xuICAgIGNhc2UgJ0RlbGV0ZSc6XG4gICAgICByZXR1cm4gYXV0aG9yaXplUnVsZXMoc2VjdXJpdHlHcm91cElkLCBhY2NvdW50KTtcbiAgfVxufVxuYXN5bmMgZnVuY3Rpb24gb25VcGRhdGUoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlVXBkYXRlRXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3Qgb2xkU2cgPSBldmVudC5PbGRSZXNvdXJjZVByb3BlcnRpZXMuRGVmYXVsdFNlY3VyaXR5R3JvdXBJZDtcbiAgY29uc3QgbmV3U2cgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuRGVmYXVsdFNlY3VyaXR5R3JvdXBJZDtcbiAgaWYgKG9sZFNnICE9PSBuZXdTZykge1xuICAgIGF3YWl0IGF1dGhvcml6ZVJ1bGVzKG9sZFNnLCBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuQWNjb3VudCk7XG4gICAgYXdhaXQgcmV2b2tlUnVsZXMobmV3U2csIGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5BY2NvdW50KTtcbiAgfVxuICByZXR1cm47XG59XG5cbi8qKlxuICogUmV2b2tlIGJvdGggaW5ncmVzcyBhbmQgZWdyZXNzIHJ1bGVzXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJldm9rZVJ1bGVzKGdyb3VwSWQ6IHN0cmluZywgYWNjb3VudDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IGVjMi5yZXZva2VTZWN1cml0eUdyb3VwRWdyZXNzKGVncmVzc1J1bGVQYXJhbXMoZ3JvdXBJZCkpO1xuICBhd2FpdCBlYzIucmV2b2tlU2VjdXJpdHlHcm91cEluZ3Jlc3MoaW5ncmVzc1J1bGVQYXJhbXMoZ3JvdXBJZCwgYWNjb3VudCkpO1xuICByZXR1cm47XG59XG5cbi8qKlxuICogQXV0aG9yaXplIGJvdGggaW5ncmVzcyBhbmQgZWdyZXNzIHJ1bGVzXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGF1dGhvcml6ZVJ1bGVzKGdyb3VwSWQ6IHN0cmluZywgYWNjb3VudDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IGVjMi5hdXRob3JpemVTZWN1cml0eUdyb3VwSW5ncmVzcyhpbmdyZXNzUnVsZVBhcmFtcyhncm91cElkLCBhY2NvdW50KSk7XG4gIGF3YWl0IGVjMi5hdXRob3JpemVTZWN1cml0eUdyb3VwRWdyZXNzKGVncmVzc1J1bGVQYXJhbXMoZ3JvdXBJZCkpO1xuICByZXR1cm47XG59XG4iXX0= \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/__entrypoint__.js b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/__entrypoint__.js new file mode 100644 index 0000000000000..1e64dba70bdc0 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/__entrypoint__.js @@ -0,0 +1,147 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.withRetries = exports.handler = exports.external = void 0; +const https = require("https"); +const url = require("url"); +// for unit tests +exports.external = { + sendHttpRequest: defaultSendHttpRequest, + log: defaultLog, + includeStackTraces: true, + userHandlerIndex: './index', +}; +const CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; +const MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; +async function handler(event, context) { + const sanitizedEvent = { ...event, ResponseURL: '...' }; + exports.external.log(JSON.stringify(sanitizedEvent, undefined, 2)); + // ignore DELETE event when the physical resource ID is the marker that + // indicates that this DELETE is a subsequent DELETE to a failed CREATE + // operation. + if (event.RequestType === 'Delete' && event.PhysicalResourceId === CREATE_FAILED_PHYSICAL_ID_MARKER) { + exports.external.log('ignoring DELETE event caused by a failed CREATE event'); + await submitResponse('SUCCESS', event); + return; + } + try { + // invoke the user handler. this is intentionally inside the try-catch to + // ensure that if there is an error it's reported as a failure to + // cloudformation (otherwise cfn waits). + // eslint-disable-next-line @typescript-eslint/no-require-imports + const userHandler = require(exports.external.userHandlerIndex).handler; + const result = await userHandler(sanitizedEvent, context); + // validate user response and create the combined event + const responseEvent = renderResponse(event, result); + // submit to cfn as success + await submitResponse('SUCCESS', responseEvent); + } + catch (e) { + const resp = { + ...event, + Reason: exports.external.includeStackTraces ? e.stack : e.message, + }; + if (!resp.PhysicalResourceId) { + // special case: if CREATE fails, which usually implies, we usually don't + // have a physical resource id. in this case, the subsequent DELETE + // operation does not have any meaning, and will likely fail as well. to + // address this, we use a marker so the provider framework can simply + // ignore the subsequent DELETE. + if (event.RequestType === 'Create') { + exports.external.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); + resp.PhysicalResourceId = CREATE_FAILED_PHYSICAL_ID_MARKER; + } + else { + // otherwise, if PhysicalResourceId is not specified, something is + // terribly wrong because all other events should have an ID. + exports.external.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(event)}`); + } + } + // this is an actual error, fail the activity altogether and exist. + await submitResponse('FAILED', resp); + } +} +exports.handler = handler; +function renderResponse(cfnRequest, handlerResponse = {}) { + // if physical ID is not returned, we have some defaults for you based + // on the request type. + const physicalResourceId = handlerResponse.PhysicalResourceId ?? cfnRequest.PhysicalResourceId ?? cfnRequest.RequestId; + // if we are in DELETE and physical ID was changed, it's an error. + if (cfnRequest.RequestType === 'Delete' && physicalResourceId !== cfnRequest.PhysicalResourceId) { + throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${handlerResponse.PhysicalResourceId}" during deletion`); + } + // merge request event and result event (result prevails). + return { + ...cfnRequest, + ...handlerResponse, + PhysicalResourceId: physicalResourceId, + }; +} +async function submitResponse(status, event) { + const json = { + Status: status, + Reason: event.Reason ?? status, + StackId: event.StackId, + RequestId: event.RequestId, + PhysicalResourceId: event.PhysicalResourceId || MISSING_PHYSICAL_ID_MARKER, + LogicalResourceId: event.LogicalResourceId, + NoEcho: event.NoEcho, + Data: event.Data, + }; + exports.external.log('submit response to cloudformation', json); + const responseBody = JSON.stringify(json); + const parsedUrl = url.parse(event.ResponseURL); + const req = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: 'PUT', + headers: { + 'content-type': '', + 'content-length': Buffer.byteLength(responseBody, 'utf8'), + }, + }; + const retryOptions = { + attempts: 5, + sleep: 1000, + }; + await withRetries(retryOptions, exports.external.sendHttpRequest)(req, responseBody); +} +async function defaultSendHttpRequest(options, responseBody) { + return new Promise((resolve, reject) => { + try { + const request = https.request(options, _ => resolve()); + request.on('error', reject); + request.write(responseBody); + request.end(); + } + catch (e) { + reject(e); + } + }); +} +function defaultLog(fmt, ...params) { + // eslint-disable-next-line no-console + console.log(fmt, ...params); +} +function withRetries(options, fn) { + return async (...xs) => { + let attempts = options.attempts; + let ms = options.sleep; + while (true) { + try { + return await fn(...xs); + } + catch (e) { + if (attempts-- <= 0) { + throw e; + } + await sleep(Math.floor(Math.random() * ms)); + ms *= 2; + } + } + }; +} +exports.withRetries = withRetries; +async function sleep(ms) { + return new Promise((ok) => setTimeout(ok, ms)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBRTNCLGlCQUFpQjtBQUNKLFFBQUEsUUFBUSxHQUFHO0lBQ3RCLGVBQWUsRUFBRSxzQkFBc0I7SUFDdkMsR0FBRyxFQUFFLFVBQVU7SUFDZixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGdCQUFnQixFQUFFLFNBQVM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sZ0NBQWdDLEdBQUcsd0RBQXdELENBQUM7QUFDbEcsTUFBTSwwQkFBMEIsR0FBRyw4REFBOEQsQ0FBQztBQVczRixLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQWtELEVBQUUsT0FBMEI7SUFDMUcsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDeEQsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFM0QsdUVBQXVFO0lBQ3ZFLHVFQUF1RTtJQUN2RSxhQUFhO0lBQ2IsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssZ0NBQWdDLEVBQUU7UUFDbkcsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUN0RSxNQUFNLGNBQWMsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkMsT0FBTztLQUNSO0lBRUQsSUFBSTtRQUNGLHlFQUF5RTtRQUN6RSxpRUFBaUU7UUFDakUsd0NBQXdDO1FBQ3hDLGlFQUFpRTtRQUNqRSxNQUFNLFdBQVcsR0FBWSxPQUFPLENBQUMsZ0JBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxNQUFNLE1BQU0sR0FBRyxNQUFNLFdBQVcsQ0FBQyxjQUFjLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFMUQsdURBQXVEO1FBQ3ZELE1BQU0sYUFBYSxHQUFHLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFcEQsMkJBQTJCO1FBQzNCLE1BQU0sY0FBYyxDQUFDLFNBQVMsRUFBRSxhQUFhLENBQUMsQ0FBQztLQUNoRDtJQUFDLE9BQU8sQ0FBTSxFQUFFO1FBQ2YsTUFBTSxJQUFJLEdBQWE7WUFDckIsR0FBRyxLQUFLO1lBQ1IsTUFBTSxFQUFFLGdCQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPO1NBQzFELENBQUM7UUFFRixJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFO1lBQzVCLHlFQUF5RTtZQUN6RSxtRUFBbUU7WUFDbkUsd0VBQXdFO1lBQ3hFLHFFQUFxRTtZQUNyRSxnQ0FBZ0M7WUFDaEMsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtnQkFDbEMsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsNEdBQTRHLENBQUMsQ0FBQztnQkFDM0gsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGdDQUFnQyxDQUFDO2FBQzVEO2lCQUFNO2dCQUNMLGtFQUFrRTtnQkFDbEUsNkRBQTZEO2dCQUM3RCxnQkFBUSxDQUFDLEdBQUcsQ0FBQyw2REFBNkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDcEc7U0FDRjtRQUVELG1FQUFtRTtRQUNuRSxNQUFNLGNBQWMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7S0FDdEM7QUFDSCxDQUFDO0FBbkRELDBCQW1EQztBQUVELFNBQVMsY0FBYyxDQUNyQixVQUF5RixFQUN6RixrQkFBMEMsRUFBRztJQUU3QyxzRUFBc0U7SUFDdEUsdUJBQXVCO0lBQ3ZCLE1BQU0sa0JBQWtCLEdBQUcsZUFBZSxDQUFDLGtCQUFrQixJQUFJLFVBQVUsQ0FBQyxrQkFBa0IsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDO0lBRXZILGtFQUFrRTtJQUNsRSxJQUFJLFVBQVUsQ0FBQyxXQUFXLEtBQUssUUFBUSxJQUFJLGtCQUFrQixLQUFLLFVBQVUsQ0FBQyxrQkFBa0IsRUFBRTtRQUMvRixNQUFNLElBQUksS0FBSyxDQUFDLHdEQUF3RCxVQUFVLENBQUMsa0JBQWtCLFNBQVMsZUFBZSxDQUFDLGtCQUFrQixtQkFBbUIsQ0FBQyxDQUFDO0tBQ3RLO0lBRUQsMERBQTBEO0lBQzFELE9BQU87UUFDTCxHQUFHLFVBQVU7UUFDYixHQUFHLGVBQWU7UUFDbEIsa0JBQWtCLEVBQUUsa0JBQWtCO0tBQ3ZDLENBQUM7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLGNBQWMsQ0FBQyxNQUE0QixFQUFFLEtBQWU7SUFDekUsTUFBTSxJQUFJLEdBQW1EO1FBQzNELE1BQU0sRUFBRSxNQUFNO1FBQ2QsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLElBQUksTUFBTTtRQUM5QixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87UUFDdEIsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1FBQzFCLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSwwQkFBMEI7UUFDMUUsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtRQUMxQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO0tBQ2pCLENBQUM7SUFFRixnQkFBUSxDQUFDLEdBQUcsQ0FBQyxtQ0FBbUMsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUV4RCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFDLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQy9DLE1BQU0sR0FBRyxHQUFHO1FBQ1YsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO1FBQzVCLElBQUksRUFBRSxTQUFTLENBQUMsSUFBSTtRQUNwQixNQUFNLEVBQUUsS0FBSztRQUNiLE9BQU8sRUFBRTtZQUNQLGNBQWMsRUFBRSxFQUFFO1lBQ2xCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQztTQUMxRDtLQUNGLENBQUM7SUFFRixNQUFNLFlBQVksR0FBRztRQUNuQixRQUFRLEVBQUUsQ0FBQztRQUNYLEtBQUssRUFBRSxJQUFJO0tBQ1osQ0FBQztJQUNGLE1BQU0sV0FBVyxDQUFDLFlBQVksRUFBRSxnQkFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsQ0FBQztBQUMvRSxDQUFDO0FBRUQsS0FBSyxVQUFVLHNCQUFzQixDQUFDLE9BQTZCLEVBQUUsWUFBb0I7SUFDdkYsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNyQyxJQUFJO1lBQ0YsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDNUIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1NBQ2Y7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNYO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsR0FBVyxFQUFFLEdBQUcsTUFBYTtJQUMvQyxzQ0FBc0M7SUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQztBQUM5QixDQUFDO0FBU0QsU0FBZ0IsV0FBVyxDQUEwQixPQUFxQixFQUFFLEVBQTRCO0lBQ3RHLE9BQU8sS0FBSyxFQUFFLEdBQUcsRUFBSyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLE9BQU8sSUFBSSxFQUFFO1lBQ1gsSUFBSTtnQkFDRixPQUFPLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDeEI7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRTtvQkFDbkIsTUFBTSxDQUFDLENBQUM7aUJBQ1Q7Z0JBQ0QsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDNUMsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNUO1NBQ0Y7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDO0FBaEJELGtDQWdCQztBQUVELEtBQUssVUFBVSxLQUFLLENBQUMsRUFBVTtJQUM3QixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDakQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG4vLyBmb3IgdW5pdCB0ZXN0c1xuZXhwb3J0IGNvbnN0IGV4dGVybmFsID0ge1xuICBzZW5kSHR0cFJlcXVlc3Q6IGRlZmF1bHRTZW5kSHR0cFJlcXVlc3QsXG4gIGxvZzogZGVmYXVsdExvZyxcbiAgaW5jbHVkZVN0YWNrVHJhY2VzOiB0cnVlLFxuICB1c2VySGFuZGxlckluZGV4OiAnLi9pbmRleCcsXG59O1xuXG5jb25zdCBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUiA9ICdBV1NDREs6OkN1c3RvbVJlc291cmNlUHJvdmlkZXJGcmFtZXdvcms6OkNSRUFURV9GQUlMRUQnO1xuY29uc3QgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpNSVNTSU5HX1BIWVNJQ0FMX0lEJztcblxuZXhwb3J0IHR5cGUgUmVzcG9uc2UgPSBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgSGFuZGxlclJlc3BvbnNlO1xuZXhwb3J0IHR5cGUgSGFuZGxlciA9IChldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCwgY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpID0+IFByb21pc2U8SGFuZGxlclJlc3BvbnNlIHwgdm9pZD47XG5leHBvcnQgdHlwZSBIYW5kbGVyUmVzcG9uc2UgPSB1bmRlZmluZWQgfCB7XG4gIERhdGE/OiBhbnk7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgUmVhc29uPzogc3RyaW5nO1xuICBOb0VjaG8/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIGNvbnRleHQ6IEFXU0xhbWJkYS5Db250ZXh0KSB7XG4gIGNvbnN0IHNhbml0aXplZEV2ZW50ID0geyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH07XG4gIGV4dGVybmFsLmxvZyhKU09OLnN0cmluZ2lmeShzYW5pdGl6ZWRFdmVudCwgdW5kZWZpbmVkLCAyKSk7XG5cbiAgLy8gaWdub3JlIERFTEVURSBldmVudCB3aGVuIHRoZSBwaHlzaWNhbCByZXNvdXJjZSBJRCBpcyB0aGUgbWFya2VyIHRoYXRcbiAgLy8gaW5kaWNhdGVzIHRoYXQgdGhpcyBERUxFVEUgaXMgYSBzdWJzZXF1ZW50IERFTEVURSB0byBhIGZhaWxlZCBDUkVBVEVcbiAgLy8gb3BlcmF0aW9uLlxuICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9PT0gQ1JFQVRFX0ZBSUxFRF9QSFlTSUNBTF9JRF9NQVJLRVIpIHtcbiAgICBleHRlcm5hbC5sb2coJ2lnbm9yaW5nIERFTEVURSBldmVudCBjYXVzZWQgYnkgYSBmYWlsZWQgQ1JFQVRFIGV2ZW50Jyk7XG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBpbnZva2UgdGhlIHVzZXIgaGFuZGxlci4gdGhpcyBpcyBpbnRlbnRpb25hbGx5IGluc2lkZSB0aGUgdHJ5LWNhdGNoIHRvXG4gICAgLy8gZW5zdXJlIHRoYXQgaWYgdGhlcmUgaXMgYW4gZXJyb3IgaXQncyByZXBvcnRlZCBhcyBhIGZhaWx1cmUgdG9cbiAgICAvLyBjbG91ZGZvcm1hdGlvbiAob3RoZXJ3aXNlIGNmbiB3YWl0cykuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCB1c2VySGFuZGxlcjogSGFuZGxlciA9IHJlcXVpcmUoZXh0ZXJuYWwudXNlckhhbmRsZXJJbmRleCkuaGFuZGxlcjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB1c2VySGFuZGxlcihzYW5pdGl6ZWRFdmVudCwgY29udGV4dCk7XG5cbiAgICAvLyB2YWxpZGF0ZSB1c2VyIHJlc3BvbnNlIGFuZCBjcmVhdGUgdGhlIGNvbWJpbmVkIGV2ZW50XG4gICAgY29uc3QgcmVzcG9uc2VFdmVudCA9IHJlbmRlclJlc3BvbnNlKGV2ZW50LCByZXN1bHQpO1xuXG4gICAgLy8gc3VibWl0IHRvIGNmbiBhcyBzdWNjZXNzXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCByZXNwb25zZUV2ZW50KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgY29uc3QgcmVzcDogUmVzcG9uc2UgPSB7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIFJlYXNvbjogZXh0ZXJuYWwuaW5jbHVkZVN0YWNrVHJhY2VzID8gZS5zdGFjayA6IGUubWVzc2FnZSxcbiAgICB9O1xuXG4gICAgaWYgKCFyZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCkge1xuICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgLy8gaGF2ZSBhIHBoeXNpY2FsIHJlc291cmNlIGlkLiBpbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXF1ZW50IERFTEVURVxuICAgICAgLy8gb3BlcmF0aW9uIGRvZXMgbm90IGhhdmUgYW55IG1lYW5pbmcsIGFuZCB3aWxsIGxpa2VseSBmYWlsIGFzIHdlbGwuIHRvXG4gICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgIC8vIGlnbm9yZSB0aGUgc3Vic2VxdWVudCBERUxFVEUuXG4gICAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnKSB7XG4gICAgICAgIGV4dGVybmFsLmxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICByZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gb3RoZXJ3aXNlLCBpZiBQaHlzaWNhbFJlc291cmNlSWQgaXMgbm90IHNwZWNpZmllZCwgc29tZXRoaW5nIGlzXG4gICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgZXh0ZXJuYWwubG9nKGBFUlJPUjogTWFsZm9ybWVkIGV2ZW50LiBcIlBoeXNpY2FsUmVzb3VyY2VJZFwiIGlzIHJlcXVpcmVkOiAke0pTT04uc3RyaW5naWZ5KGV2ZW50KX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyB0aGlzIGlzIGFuIGFjdHVhbCBlcnJvciwgZmFpbCB0aGUgYWN0aXZpdHkgYWx0b2dldGhlciBhbmQgZXhpc3QuXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ0ZBSUxFRCcsIHJlc3ApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlbmRlclJlc3BvbnNlKFxuICBjZm5SZXF1ZXN0OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgeyBQaHlzaWNhbFJlc291cmNlSWQ/OiBzdHJpbmcgfSxcbiAgaGFuZGxlclJlc3BvbnNlOiB2b2lkIHwgSGFuZGxlclJlc3BvbnNlID0geyB9KTogUmVzcG9uc2Uge1xuXG4gIC8vIGlmIHBoeXNpY2FsIElEIGlzIG5vdCByZXR1cm5lZCwgd2UgaGF2ZSBzb21lIGRlZmF1bHRzIGZvciB5b3UgYmFzZWRcbiAgLy8gb24gdGhlIHJlcXVlc3QgdHlwZS5cbiAgY29uc3QgcGh5c2ljYWxSZXNvdXJjZUlkID0gaGFuZGxlclJlc3BvbnNlLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlJlcXVlc3RJZDtcblxuICAvLyBpZiB3ZSBhcmUgaW4gREVMRVRFIGFuZCBwaHlzaWNhbCBJRCB3YXMgY2hhbmdlZCwgaXQncyBhbiBlcnJvci5cbiAgaWYgKGNmblJlcXVlc3QuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIHBoeXNpY2FsUmVzb3VyY2VJZCAhPT0gY2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERFTEVURTogY2Fubm90IGNoYW5nZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSBcIiR7Y2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWR9XCIgdG8gXCIke2hhbmRsZXJSZXNwb25zZS5QaHlzaWNhbFJlc291cmNlSWR9XCIgZHVyaW5nIGRlbGV0aW9uYCk7XG4gIH1cblxuICAvLyBtZXJnZSByZXF1ZXN0IGV2ZW50IGFuZCByZXN1bHQgZXZlbnQgKHJlc3VsdCBwcmV2YWlscykuXG4gIHJldHVybiB7XG4gICAgLi4uY2ZuUmVxdWVzdCxcbiAgICAuLi5oYW5kbGVyUmVzcG9uc2UsXG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN1Ym1pdFJlc3BvbnNlKHN0YXR1czogJ1NVQ0NFU1MnIHwgJ0ZBSUxFRCcsIGV2ZW50OiBSZXNwb25zZSkge1xuICBjb25zdCBqc29uOiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlID0ge1xuICAgIFN0YXR1czogc3RhdHVzLFxuICAgIFJlYXNvbjogZXZlbnQuUmVhc29uID8/IHN0YXR1cyxcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkIHx8IE1JU1NJTkdfUEhZU0lDQUxfSURfTUFSS0VSLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBOb0VjaG86IGV2ZW50Lk5vRWNobyxcbiAgICBEYXRhOiBldmVudC5EYXRhLFxuICB9O1xuXG4gIGV4dGVybmFsLmxvZygnc3VibWl0IHJlc3BvbnNlIHRvIGNsb3VkZm9ybWF0aW9uJywganNvbik7XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoanNvbik7XG4gIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShldmVudC5SZXNwb25zZVVSTCk7XG4gIGNvbnN0IHJlcSA9IHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogQnVmZmVyLmJ5dGVMZW5ndGgocmVzcG9uc2VCb2R5LCAndXRmOCcpLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3QgcmV0cnlPcHRpb25zID0ge1xuICAgIGF0dGVtcHRzOiA1LFxuICAgIHNsZWVwOiAxMDAwLFxuICB9O1xuICBhd2FpdCB3aXRoUmV0cmllcyhyZXRyeU9wdGlvbnMsIGV4dGVybmFsLnNlbmRIdHRwUmVxdWVzdCkocmVxLCByZXNwb25zZUJvZHkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0U2VuZEh0dHBSZXF1ZXN0KG9wdGlvbnM6IGh0dHBzLlJlcXVlc3RPcHRpb25zLCByZXNwb25zZUJvZHk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCBfID0+IHJlc29sdmUoKSk7XG4gICAgICByZXF1ZXN0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICByZXF1ZXN0LndyaXRlKHJlc3BvbnNlQm9keSk7XG4gICAgICByZXF1ZXN0LmVuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWZhdWx0TG9nKGZtdDogc3RyaW5nLCAuLi5wYXJhbXM6IGFueVtdKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gIGNvbnNvbGUubG9nKGZtdCwgLi4ucGFyYW1zKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXRyeU9wdGlvbnMge1xuICAvKiogSG93IG1hbnkgcmV0cmllcyAod2lsbCBhdCBsZWFzdCB0cnkgb25jZSkgKi9cbiAgcmVhZG9ubHkgYXR0ZW1wdHM6IG51bWJlcjtcbiAgLyoqIFNsZWVwIGJhc2UsIGluIG1zICovXG4gIHJlYWRvbmx5IHNsZWVwOiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB3aXRoUmV0cmllczxBIGV4dGVuZHMgQXJyYXk8YW55PiwgQj4ob3B0aW9uczogUmV0cnlPcHRpb25zLCBmbjogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+KTogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+IHtcbiAgcmV0dXJuIGFzeW5jICguLi54czogQSkgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IG9wdGlvbnMuYXR0ZW1wdHM7XG4gICAgbGV0IG1zID0gb3B0aW9ucy5zbGVlcDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGZuKC4uLnhzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGF0dGVtcHRzLS0gPD0gMCkge1xuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgc2xlZXAoTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbXMpKTtcbiAgICAgICAgbXMgKj0gMjtcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChvaykgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/index.js new file mode 100644 index 0000000000000..013bcaffd8fe5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292/index.js @@ -0,0 +1 @@ +"use strict";var I=Object.create;var t=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty;var G=(r,e)=>{for(var o in e)t(r,o,{get:e[o],enumerable:!0})},n=(r,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of P(e))!l.call(r,s)&&s!==o&&t(r,s,{get:()=>e[s],enumerable:!(i=y(e,s))||i.enumerable});return r};var R=(r,e,o)=>(o=r!=null?I(g(r)):{},n(e||!r||!r.__esModule?t(o,"default",{value:r,enumerable:!0}):o,r)),S=r=>n(t({},"__esModule",{value:!0}),r);var k={};G(k,{handler:()=>f});module.exports=S(k);var a=R(require("@aws-sdk/client-ec2")),u=new a.EC2({});function c(r,e){return{GroupId:r,IpPermissions:[{UserIdGroupPairs:[{GroupId:r,UserId:e}],IpProtocol:"-1"}]}}function d(r){return{GroupId:r,IpPermissions:[{IpRanges:[{CidrIp:"0.0.0.0/0"}],IpProtocol:"-1"}]}}async function f(r){let e=r.ResourceProperties.DefaultSecurityGroupId,o=r.ResourceProperties.Account;switch(r.RequestType){case"Create":return p(e,o);case"Update":return h(r);case"Delete":return m(e,o)}}async function h(r){let e=r.OldResourceProperties.DefaultSecurityGroupId,o=r.ResourceProperties.DefaultSecurityGroupId;e!==o&&(await m(e,r.ResourceProperties.Account),await p(o,r.ResourceProperties.Account))}async function p(r,e){try{await u.revokeSecurityGroupEgress(d(r))}catch(o){if(o.name!=="InvalidPermission.NotFound")throw o}try{await u.revokeSecurityGroupIngress(c(r,e))}catch(o){if(o.name!=="InvalidPermission.NotFound")throw o}}async function m(r,e){await u.authorizeSecurityGroupIngress(c(r,e)),await u.authorizeSecurityGroupEgress(d(r))}0&&(module.exports={handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/aws-cdk-ecs-integration-test-stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/aws-cdk-ecs-integration-test-stack.assets.json index 984639eb21536..bcad7cf054407 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/aws-cdk-ecs-integration-test-stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/aws-cdk-ecs-integration-test-stack.assets.json @@ -1,20 +1,20 @@ { - "version": "33.0.0", + "version": "36.0.0", "files": { - "18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837": { + "4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292": { "source": { - "path": "asset.18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837", + "path": "asset.4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837.zip", + "objectKey": "4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "545f32fe4d096c69d7a026dfd881c64a303db97294fafe370363435268fdeaf2": { + "5435fe897ca96c0d80f4504e8c74c97c3426a99acb78aa9224284f09b8676803": { "source": { "path": "aws-cdk-ecs-integration-test-stack.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "545f32fe4d096c69d7a026dfd881c64a303db97294fafe370363435268fdeaf2.json", + "objectKey": "5435fe897ca96c0d80f4504e8c74c97c3426a99acb78aa9224284f09b8676803.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/aws-cdk-ecs-integration-test-stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/aws-cdk-ecs-integration-test-stack.template.json index 71019c33c1e02..0bcb0d5ae17ef 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/aws-cdk-ecs-integration-test-stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/aws-cdk-ecs-integration-test-stack.template.json @@ -489,7 +489,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "18d379b052acd60e0d086d5b19d9bef956ebc0bd018c5570960125aab0c7f837.zip" + "S3Key": "4554b47be6f57b68c6c7a7391dcc73894866d2377fe174883351e7639097f292.zip" }, "Timeout": 900, "MemorySize": 128, @@ -901,7 +901,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572F6CCD921": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB2590F4035E": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -913,11 +913,11 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { "Endpoint": { @@ -928,11 +928,11 @@ }, "Protocol": "lambda", "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -975,7 +975,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -999,7 +999,7 @@ "HeartbeatTimeout": 300, "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/awscdkecsintegrationteststackTaskDefinitionPlacementConstraintsDefaultTestDeployAssert906A0CF3.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/awscdkecsintegrationteststackTaskDefinitionPlacementConstraintsDefaultTestDeployAssert906A0CF3.assets.json index d813da11ec61b..40bed7791ce92 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/awscdkecsintegrationteststackTaskDefinitionPlacementConstraintsDefaultTestDeployAssert906A0CF3.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/awscdkecsintegrationteststackTaskDefinitionPlacementConstraintsDefaultTestDeployAssert906A0CF3.assets.json @@ -1,5 +1,5 @@ { - "version": "33.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/cdk.out index 560dae10d018f..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"33.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/integ.json index e60131d94b5a7..6302b513128b5 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "33.0.0", + "version": "36.0.0", "testCases": { "aws-cdk-ecs-integration-test-stack/TaskDefinitionPlacementConstraints/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/manifest.json index f4c8a9383b37e..93930255d2ddc 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "33.0.0", + "version": "36.0.0", "artifacts": { "awscdkecsintegrationteststackTaskDefinitionPlacementConstraintsDefaultTestDeployAssert906A0CF3.assets": { "type": "cdk:asset-manifest", @@ -14,6 +14,7 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "awscdkecsintegrationteststackTaskDefinitionPlacementConstraintsDefaultTestDeployAssert906A0CF3.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}", @@ -61,10 +62,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-cdk-ecs-integration-test-stack.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}/545f32fe4d096c69d7a026dfd881c64a303db97294fafe370363435268fdeaf2.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5435fe897ca96c0d80f4504e8c74c97c3426a99acb78aa9224284f09b8676803.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -296,22 +298,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572": [ + "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB25": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572F6CCD921" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB2590F4035E" } ], - "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -367,6 +369,33 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572F6CCD921": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572F6CCD921", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "aws-cdk-ecs-integration-test-stack" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/tree.json index e93f9a3dffa25..3106477215bb8 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/ec2/integ.task-definition-placement-constraints.js.snapshot/tree.json @@ -699,7 +699,7 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.CustomResourceProvider", + "fqn": "aws-cdk-lib.CustomResourceProviderBase", "version": "0.0.0" } }, @@ -1262,9 +1262,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572": { - "id": "AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicD01B2572", + "AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB25": { + "id": "AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB25", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awscdkecsintegrationteststackEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookEADFDB25", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1277,7 +1277,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1286,13 +1286,13 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { @@ -1304,7 +1304,7 @@ }, "protocol": "lambda", "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -1328,20 +1328,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.69" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-cdk-ecs-integration-test-stack/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1423,7 +1423,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1467,7 +1467,7 @@ "heartbeatTimeout": 300, "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1669,7 +1669,7 @@ "path": "aws-cdk-ecs-integration-test-stack/TaskDefinitionPlacementConstraints/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.69" + "version": "10.3.0" } }, "DeployAssert": { @@ -1737,7 +1737,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.69" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/integ-ecs-neuron-ami.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/integ-ecs-neuron-ami.assets.json index ac090feb99171..b55ca82ae6196 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/integ-ecs-neuron-ami.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/integ-ecs-neuron-ami.assets.json @@ -1,7 +1,7 @@ { "version": "36.0.0", "files": { - "758add4abf782a712eea18984d2d3f66778882c56d0e19e18a2eb0a1c296430a": { + "5f58ce39886a9e5d7d7e48076324ac85b509b7fc5ab8157278631d92425d94c5": { "source": { "path": "integ-ecs-neuron-ami.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "758add4abf782a712eea18984d2d3f66778882c56d0e19e18a2eb0a1c296430a.json", + "objectKey": "5f58ce39886a9e5d7d7e48076324ac85b509b7fc5ab8157278631d92425d94c5.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/integ-ecs-neuron-ami.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/integ-ecs-neuron-ami.template.json index 72346678779af..a8e7cdcc0b9f1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/integ-ecs-neuron-ami.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/integ-ecs-neuron-ami.template.json @@ -796,7 +796,7 @@ "ASGDrainECSHookFunctionServiceRoleC12963BB" ] }, - "ASGDrainECSHookFunctionAllowInvokeintegecsneuronamiASGLifecycleHookDrainHookTopic1002D76741A20C61": { + "ASGDrainECSHookFunctionAllowInvokeintegecsneuronamiASGLifecycleHookDrainHookTopicLifecycleHookDrainHook637694D75CF55332": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -808,11 +808,11 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, - "ASGDrainECSHookFunctionTopicD6FC59F7": { + "ASGDrainECSHookFunctionTopicLifecycleHookDrainHook8B240409": { "Type": "AWS::SNS::Subscription", "Properties": { "Endpoint": { @@ -823,11 +823,11 @@ }, "Protocol": "lambda", "TopicArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, - "ASGLifecycleHookDrainHookTopicA8AD4ACB": { + "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -870,7 +870,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } ], @@ -894,7 +894,7 @@ "HeartbeatTimeout": 300, "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/manifest.json index b9e92d6e50311..8063ba79cce1d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/manifest.json @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/758add4abf782a712eea18984d2d3f66778882c56d0e19e18a2eb0a1c296430a.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5f58ce39886a9e5d7d7e48076324ac85b509b7fc5ab8157278631d92425d94c5.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -238,22 +238,22 @@ "data": "ASGDrainECSHookFunction5F24CF4D" } ], - "/integ-ecs-neuron-ami/ASG/DrainECSHook/Function/AllowInvoke:integecsneuronamiASGLifecycleHookDrainHookTopic1002D767": [ + "/integ-ecs-neuron-ami/ASG/DrainECSHook/Function/AllowInvoke:integecsneuronamiASGLifecycleHookDrainHookTopicLifecycleHookDrainHook637694D7": [ { "type": "aws:cdk:logicalId", - "data": "ASGDrainECSHookFunctionAllowInvokeintegecsneuronamiASGLifecycleHookDrainHookTopic1002D76741A20C61" + "data": "ASGDrainECSHookFunctionAllowInvokeintegecsneuronamiASGLifecycleHookDrainHookTopicLifecycleHookDrainHook637694D75CF55332" } ], - "/integ-ecs-neuron-ami/ASG/DrainECSHook/Function/Topic/Resource": [ + "/integ-ecs-neuron-ami/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ASGDrainECSHookFunctionTopicD6FC59F7" + "data": "ASGDrainECSHookFunctionTopicLifecycleHookDrainHook8B240409" } ], - "/integ-ecs-neuron-ami/ASG/LifecycleHookDrainHook/Topic/Resource": [ + "/integ-ecs-neuron-ami/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "data": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } ], "/integ-ecs-neuron-ami/ASG/LifecycleHookDrainHook/Role/Resource": [ @@ -297,6 +297,33 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "ASGDrainECSHookFunctionAllowInvokeintegecsneuronamiASGLifecycleHookDrainHookTopic1002D76741A20C61": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGDrainECSHookFunctionAllowInvokeintegecsneuronamiASGLifecycleHookDrainHookTopic1002D76741A20C61", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ASGDrainECSHookFunctionTopicD6FC59F7": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGDrainECSHookFunctionTopicD6FC59F7", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ASGLifecycleHookDrainHookTopicA8AD4ACB": [ + { + "type": "aws:cdk:logicalId", + "data": "ASGLifecycleHookDrainHookTopicA8AD4ACB", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "integ-ecs-neuron-ami" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/tree.json index c83586da093a0..6b80c0949b9e3 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-amazonlinux2-neuron-ami.js.snapshot/tree.json @@ -1238,9 +1238,9 @@ "version": "0.0.0" } }, - "AllowInvoke:integecsneuronamiASGLifecycleHookDrainHookTopic1002D767": { - "id": "AllowInvoke:integecsneuronamiASGLifecycleHookDrainHookTopic1002D767", - "path": "integ-ecs-neuron-ami/ASG/DrainECSHook/Function/AllowInvoke:integecsneuronamiASGLifecycleHookDrainHookTopic1002D767", + "AllowInvoke:integecsneuronamiASGLifecycleHookDrainHookTopicLifecycleHookDrainHook637694D7": { + "id": "AllowInvoke:integecsneuronamiASGLifecycleHookDrainHookTopicLifecycleHookDrainHook637694D7", + "path": "integ-ecs-neuron-ami/ASG/DrainECSHook/Function/AllowInvoke:integecsneuronamiASGLifecycleHookDrainHookTopicLifecycleHookDrainHook637694D7", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1253,7 +1253,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, @@ -1262,13 +1262,13 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "integ-ecs-neuron-ami/ASG/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "integ-ecs-neuron-ami/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "integ-ecs-neuron-ami/ASG/DrainECSHook/Function/Topic/Resource", + "path": "integ-ecs-neuron-ami/ASG/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { @@ -1280,7 +1280,7 @@ }, "protocol": "lambda", "topicArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } }, @@ -1311,13 +1311,13 @@ "id": "LifecycleHookDrainHook", "path": "integ-ecs-neuron-ami/ASG/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "integ-ecs-neuron-ami/ASG/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "integ-ecs-neuron-ami/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "integ-ecs-neuron-ami/ASG/LifecycleHookDrainHook/Topic/Resource", + "path": "integ-ecs-neuron-ami/ASG/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1399,7 +1399,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" } } ], @@ -1443,7 +1443,7 @@ "heartbeatTimeout": 300, "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "ASGLifecycleHookDrainHookTopicA8AD4ACB" + "Ref": "ASGLifecycleHookDrainHookTopicLifecycleHookDrainHook12DCC569" }, "roleArn": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/aws-ecs-integ-bottlerocket-nvidia-ami.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/aws-ecs-integ-bottlerocket-nvidia-ami.assets.json index 1ada4a62eae05..f82f232110c7d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/aws-ecs-integ-bottlerocket-nvidia-ami.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/aws-ecs-integ-bottlerocket-nvidia-ami.assets.json @@ -1,7 +1,7 @@ { "version": "36.0.0", "files": { - "25ecc9ee1f79cd8a912202279ab524c1d49216ee0be93a5179ef19f50cd1b1ba": { + "9a1281f5675a001c8abfae3b7bf47b04b848588d5f82e85ae58da71660eb4492": { "source": { "path": "aws-ecs-integ-bottlerocket-nvidia-ami.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "25ecc9ee1f79cd8a912202279ab524c1d49216ee0be93a5179ef19f50cd1b1ba.json", + "objectKey": "9a1281f5675a001c8abfae3b7bf47b04b848588d5f82e85ae58da71660eb4492.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/aws-ecs-integ-bottlerocket-nvidia-ami.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/aws-ecs-integ-bottlerocket-nvidia-ami.template.json index b393e63b3fec4..6f0feb6002271 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/aws-ecs-integ-bottlerocket-nvidia-ami.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/aws-ecs-integ-bottlerocket-nvidia-ami.template.json @@ -811,7 +811,7 @@ "ClusterbottlerocketasgDrainECSHookFunctionServiceRole91B0C3B3" ] }, - "ClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopic46897984C264A0A5": { + "ClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookAD5FA703FE15622C": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -823,11 +823,11 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" } } }, - "ClusterbottlerocketasgDrainECSHookFunctionTopicC875173C": { + "ClusterbottlerocketasgDrainECSHookFunctionTopicLifecycleHookDrainHook205EA218": { "Type": "AWS::SNS::Subscription", "Properties": { "Endpoint": { @@ -838,11 +838,11 @@ }, "Protocol": "lambda", "TopicArn": { - "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" } } }, - "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02": { + "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -885,7 +885,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" } } ], @@ -909,7 +909,7 @@ "HeartbeatTimeout": 300, "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/manifest.json index 28658ca520aa3..739289f251aef 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/manifest.json @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/25ecc9ee1f79cd8a912202279ab524c1d49216ee0be93a5179ef19f50cd1b1ba.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/9a1281f5675a001c8abfae3b7bf47b04b848588d5f82e85ae58da71660eb4492.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -232,22 +232,22 @@ "data": "ClusterbottlerocketasgDrainECSHookFunctionFEA27227" } ], - "/aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/AllowInvoke:awsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopic46897984": [ + "/aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/AllowInvoke:awsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookAD5FA703": [ { "type": "aws:cdk:logicalId", - "data": "ClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopic46897984C264A0A5" + "data": "ClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookAD5FA703FE15622C" } ], - "/aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ClusterbottlerocketasgDrainECSHookFunctionTopicC875173C" + "data": "ClusterbottlerocketasgDrainECSHookFunctionTopicLifecycleHookDrainHook205EA218" } ], - "/aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "data": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" } ], "/aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/LifecycleHookDrainHook/Role/Resource": [ @@ -285,6 +285,33 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "ClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopic46897984C264A0A5": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterbottlerocketasgDrainECSHookFunctionAllowInvokeawsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopic46897984C264A0A5", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ClusterbottlerocketasgDrainECSHookFunctionTopicC875173C": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterbottlerocketasgDrainECSHookFunctionTopicC875173C", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "aws-ecs-integ-bottlerocket-nvidia-ami" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/tree.json index 0f1c006667121..02b5fee6ebd30 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/integ.cluster-bottlerocket-nvidia-ami.js.snapshot/tree.json @@ -1236,9 +1236,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopic46897984": { - "id": "AllowInvoke:awsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopic46897984", - "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/AllowInvoke:awsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopic46897984", + "AllowInvoke:awsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookAD5FA703": { + "id": "AllowInvoke:awsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookAD5FA703", + "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/AllowInvoke:awsecsintegbottlerocketnvidiaamiClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHookAD5FA703", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1251,7 +1251,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" } } }, @@ -1260,13 +1260,13 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { @@ -1278,7 +1278,7 @@ }, "protocol": "lambda", "topicArn": { - "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" } } }, @@ -1309,13 +1309,13 @@ "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-bottlerocket-nvidia-ami/Cluster/bottlerocket-asg/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1397,7 +1397,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" } } ], @@ -1441,7 +1441,7 @@ "heartbeatTimeout": 300, "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopic34DF3A02" + "Ref": "ClusterbottlerocketasgLifecycleHookDrainHookTopicLifecycleHookDrainHook23DCBF85" }, "roleArn": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/EcsTestDefaultTestDeployAssert8B2741C4.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/EcsTestDefaultTestDeployAssert8B2741C4.assets.json index 50af70367c47c..a8157b72463ac 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/EcsTestDefaultTestDeployAssert8B2741C4.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/EcsTestDefaultTestDeployAssert8B2741C4.assets.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.assets.json index c22f05f52768f..85d20bfe19a3a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "4a78384a01994e654d09b7284f2044646eea91d2630aa956128e0fbed5377569": { + "044fa8dafcc926dbc71e63631023998cee5b51b85c0d50ed3d0ed3c452d9dffa": { "source": { "path": "aws-ecs-integ-ecs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "4a78384a01994e654d09b7284f2044646eea91d2630aa956128e0fbed5377569.json", + "objectKey": "044fa8dafcc926dbc71e63631023998cee5b51b85c0d50ed3d0ed3c452d9dffa.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.template.json index 1ea968ab16cc9..db47bbeae2e52 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.template.json @@ -18,9 +18,6 @@ "VpcPublicSubnet1Subnet5C2D37C4": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -44,21 +41,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTable6C95E38E": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPublicSubnet1RouteTableAssociation97140677": { @@ -75,12 +75,12 @@ "VpcPublicSubnet1DefaultRoute3DA9E72A": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } }, "DependsOn": [ @@ -102,15 +102,15 @@ "VpcPublicSubnet1NATGateway4D7517AA": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "AllocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "Tags": [ { "Key": "Name", @@ -126,9 +126,6 @@ "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -152,21 +149,24 @@ "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableB2C5B500": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } } }, "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { @@ -183,12 +183,12 @@ "VpcPrivateSubnet1DefaultRouteBE02A9ED": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -206,11 +206,11 @@ "VpcVPCGWBF912B6E": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Vpc8378EB38" - }, "InternetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "VpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -412,8 +412,6 @@ "EcsClusterDefaultAutoScalingGroupASGC1A785DB": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -425,6 +423,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -577,12 +577,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -591,6 +585,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -605,7 +605,7 @@ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA" ] }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -617,26 +617,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": { + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "Endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, - "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": { + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -679,7 +679,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -699,11 +699,11 @@ "AutoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "RoleARN": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/cdk.out index f0b901e7c06e5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/integ.json index 470e64719282c..bc94f6a9998c9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "EcsTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/manifest.json index cedde4a2124e4..2a72219530d1f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ-ecs.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ-ecs.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}/4a78384a01994e654d09b7284f2044646eea91d2630aa956128e0fbed5377569.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/044fa8dafcc926dbc71e63631023998cee5b51b85c0d50ed3d0ed3c452d9dffa.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -171,22 +172,22 @@ "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C328254CD" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394" + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook5B683808" } ], - "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } ], "/aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -285,10 +286,28 @@ "data": "CheckBootstrapVersion" } ], - "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328": [ { "type": "aws:cdk:logicalId", - "data": "EcsClusterDefaultAutoScalingGroupLaunchTemplateProfile45668F20", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AFBA77E328", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic8F34E394", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4": [ + { + "type": "aws:cdk:logicalId", + "data": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] @@ -310,6 +329,7 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "EcsTestDefaultTestDeployAssert8B2741C4.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}", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/tree.json index 6fe81814f9042..489c90d3ec22c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/tree.json @@ -45,9 +45,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -71,7 +68,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -93,15 +93,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -134,12 +134,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPublicSubnet1RouteTable6C95E38E" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "routeTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" } } }, @@ -174,15 +174,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "VpcPublicSubnet1Subnet5C2D37C4" - }, "allocationId": { "Fn::GetAtt": [ "VpcPublicSubnet1EIPD7E02669", "AllocationId" ] }, + "subnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, "tags": [ { "key": "Name", @@ -212,9 +212,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -238,7 +235,10 @@ "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -260,15 +260,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ-ecs/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } } }, "constructInfo": { @@ -301,12 +301,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + }, + "routeTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" } } }, @@ -346,11 +346,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Vpc8378EB38" - }, "internetGatewayId": { "Ref": "VpcIGWD7BA715C" + }, + "vpcId": { + "Ref": "Vpc8378EB38" } } }, @@ -568,6 +568,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -667,8 +675,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "EcsClusterDefaultAutoScalingGroupLaunchTemplate3719972A" @@ -680,6 +686,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -884,12 +892,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -898,6 +900,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole94543EDA", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -913,9 +921,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF": { - "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic0C4958AF", + "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C": { + "id": "AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsintegecsEcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook2AC6B69C", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -928,7 +936,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -937,25 +945,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" - }, "endpoint": { "Fn::GetAtt": [ "EcsClusterDefaultAutoScalingGroupDrainECSHookFunctionE17A5F5E", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } }, @@ -979,20 +987,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1074,7 +1082,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" } } ], @@ -1114,11 +1122,11 @@ "autoScalingGroupName": { "Ref": "EcsClusterDefaultAutoScalingGroupASGC1A785DB" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4" + "Ref": "EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF" }, "roleArn": { "Fn::GetAtt": [ @@ -1738,7 +1746,7 @@ "path": "EcsTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "DeployAssert": { @@ -1784,7 +1792,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/aws-sfn-tasks-ecs-ec2-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/aws-sfn-tasks-ecs-ec2-integ.assets.json index 715b1481a702b..ea8930b1e94ae 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/aws-sfn-tasks-ecs-ec2-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/aws-sfn-tasks-ecs-ec2-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "094d02f805367413b48e15531f0003d2531c3c5e3bf3f1f0d6da61227cecae4a": { + "3bd1f404412bc6c5c31271d6a255e28c1f25bc164625f6324751b49d06668b71": { "source": { "path": "aws-sfn-tasks-ecs-ec2-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "094d02f805367413b48e15531f0003d2531c3c5e3bf3f1f0d6da61227cecae4a.json", + "objectKey": "3bd1f404412bc6c5c31271d6a255e28c1f25bc164625f6324751b49d06668b71.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/aws-sfn-tasks-ecs-ec2-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/aws-sfn-tasks-ecs-ec2-integ.template.json index 63fb3851bf89d..f7b61a4d6e957 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/aws-sfn-tasks-ecs-ec2-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/aws-sfn-tasks-ecs-ec2-integ.template.json @@ -21,9 +21,6 @@ "Ec2ClusterVpcPublicSubnet1SubnetD46FD92B": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -47,21 +44,24 @@ "Key": "Name", "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "Ec2ClusterVpcPublicSubnet1RouteTableE30610F5": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "Tags": [ { "Key": "Name", "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "Ec2ClusterVpcPublicSubnet1RouteTableAssociation9C78F646": { @@ -78,12 +78,12 @@ "Ec2ClusterVpcPublicSubnet1DefaultRouteC7FBE273": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "Ec2ClusterVpcPublicSubnet1RouteTableE30610F5" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "Ec2ClusterVpcIGW605638EB" + }, + "RouteTableId": { + "Ref": "Ec2ClusterVpcPublicSubnet1RouteTableE30610F5" } }, "DependsOn": [ @@ -105,15 +105,15 @@ "Ec2ClusterVpcPublicSubnet1NATGateway79A8A839": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "Ec2ClusterVpcPublicSubnet1SubnetD46FD92B" - }, "AllocationId": { "Fn::GetAtt": [ "Ec2ClusterVpcPublicSubnet1EIPD4B5D142", "AllocationId" ] }, + "SubnetId": { + "Ref": "Ec2ClusterVpcPublicSubnet1SubnetD46FD92B" + }, "Tags": [ { "Key": "Name", @@ -129,9 +129,6 @@ "Ec2ClusterVpcPublicSubnet2Subnet207D9E5E": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -155,21 +152,24 @@ "Key": "Name", "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "Ec2ClusterVpcPublicSubnet2RouteTable44A09188": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "Tags": [ { "Key": "Name", "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "Ec2ClusterVpcPublicSubnet2RouteTableAssociation7615C6B2": { @@ -186,12 +186,12 @@ "Ec2ClusterVpcPublicSubnet2DefaultRouteEBA52256": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "Ec2ClusterVpcPublicSubnet2RouteTable44A09188" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "Ec2ClusterVpcIGW605638EB" + }, + "RouteTableId": { + "Ref": "Ec2ClusterVpcPublicSubnet2RouteTable44A09188" } }, "DependsOn": [ @@ -213,15 +213,15 @@ "Ec2ClusterVpcPublicSubnet2NATGateway302F96C0": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "Ec2ClusterVpcPublicSubnet2Subnet207D9E5E" - }, "AllocationId": { "Fn::GetAtt": [ "Ec2ClusterVpcPublicSubnet2EIP921925E6", "AllocationId" ] }, + "SubnetId": { + "Ref": "Ec2ClusterVpcPublicSubnet2Subnet207D9E5E" + }, "Tags": [ { "Key": "Name", @@ -237,9 +237,6 @@ "Ec2ClusterVpcPrivateSubnet1Subnet0AE9B91E": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -263,21 +260,24 @@ "Key": "Name", "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "Ec2ClusterVpcPrivateSubnet1RouteTable50D391D1": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "Tags": [ { "Key": "Name", "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "Ec2ClusterVpcPrivateSubnet1RouteTableAssociation1043DBDA": { @@ -294,21 +294,18 @@ "Ec2ClusterVpcPrivateSubnet1DefaultRouteD31A76F0": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "Ec2ClusterVpcPrivateSubnet1RouteTable50D391D1" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "Ec2ClusterVpcPublicSubnet1NATGateway79A8A839" + }, + "RouteTableId": { + "Ref": "Ec2ClusterVpcPrivateSubnet1RouteTable50D391D1" } } }, "Ec2ClusterVpcPrivateSubnet2Subnet16B68C19": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -332,21 +329,24 @@ "Key": "Name", "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "Ec2ClusterVpcPrivateSubnet2RouteTable22B9DAE6": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "Tags": [ { "Key": "Name", "Value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "Ec2ClusterVpcPrivateSubnet2RouteTableAssociation3AFD70F4": { @@ -363,12 +363,12 @@ "Ec2ClusterVpcPrivateSubnet2DefaultRoute22B3073E": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "Ec2ClusterVpcPrivateSubnet2RouteTable22B9DAE6" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "Ec2ClusterVpcPublicSubnet2NATGateway302F96C0" + }, + "RouteTableId": { + "Ref": "Ec2ClusterVpcPrivateSubnet2RouteTable22B9DAE6" } } }, @@ -386,11 +386,11 @@ "Ec2ClusterVpcVPCGW24F3B413": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "InternetGatewayId": { "Ref": "Ec2ClusterVpcIGW605638EB" + }, + "VpcId": { + "Ref": "Ec2ClusterVpc568127F1" } } }, @@ -589,8 +589,6 @@ "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "Ec2ClusterDefaultAutoScalingGroupLaunchTemplate346F58BE" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3" ] }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicEE9E39A29ACCEEA3": { + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook69E8851FFEF9F178": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } }, - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6": { + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook235709FD": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" - }, "Endpoint": { "Fn::GetAtt": [ "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } }, - "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30": { + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" }, "RoleARN": { "Fn::GetAtt": [ @@ -1250,12 +1250,6 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { - "RoleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] - }, "DefinitionString": { "Fn::Join": [ "", @@ -1274,6 +1268,12 @@ "\",\"TaskDefinition\":\"awssfntasksecsec2integTaskDefFAFE2BE7\",\"Overrides\":{\"ContainerOverrides\":[{\"Name\":\"TheContainer\",\"Environment\":[{\"Name\":\"SOME_KEY\",\"Value.$\":\"$.SomeKey\"}]}]},\"LaunchType\":\"EC2\"}}}}" ] ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] } }, "DependsOn": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/cdk.out index f0b901e7c06e5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/integ.json index 848b3910874f2..76b20642f0ceb 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.ec2-run-task": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/manifest.json index d21830841bd41..bcf606a041997 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-sfn-tasks-ecs-ec2-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-sfn-tasks-ecs-ec2-integ.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}/094d02f805367413b48e15531f0003d2531c3c5e3bf3f1f0d6da61227cecae4a.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/3bd1f404412bc6c5c31271d6a255e28c1f25bc164625f6324751b49d06668b71.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31" } ], - "/aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicEE9E39A2": [ + "/aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook69E8851F": [ { "type": "aws:cdk:logicalId", - "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicEE9E39A29ACCEEA3" + "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook69E8851FFEF9F178" } ], - "/aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6" + "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHook235709FD" } ], - "/aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "data": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } ], "/aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -339,10 +340,28 @@ "data": "CheckBootstrapVersion" } ], - "Ec2ClusterDefaultAutoScalingGroupLaunchTemplateProfileA74899D4": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicEE9E39A29ACCEEA3": [ { "type": "aws:cdk:logicalId", - "data": "Ec2ClusterDefaultAutoScalingGroupLaunchTemplateProfileA74899D4", + "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicEE9E39A29ACCEEA3", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6": [ + { + "type": "aws:cdk:logicalId", + "data": "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic4795E0F6", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30": [ + { + "type": "aws:cdk:logicalId", + "data": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/tree.json index dd9d7c7d9e430..c767c0f945d0b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-run-task.js.snapshot/tree.json @@ -61,9 +61,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -87,7 +84,10 @@ "key": "Name", "value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "constructInfo": { @@ -109,15 +109,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "tags": [ { "key": "Name", "value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "constructInfo": { @@ -150,12 +150,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "Ec2ClusterVpcPublicSubnet1RouteTableE30610F5" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "Ec2ClusterVpcIGW605638EB" + }, + "routeTableId": { + "Ref": "Ec2ClusterVpcPublicSubnet1RouteTableE30610F5" } } }, @@ -190,15 +190,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "Ec2ClusterVpcPublicSubnet1SubnetD46FD92B" - }, "allocationId": { "Fn::GetAtt": [ "Ec2ClusterVpcPublicSubnet1EIPD4B5D142", "AllocationId" ] }, + "subnetId": { + "Ref": "Ec2ClusterVpcPublicSubnet1SubnetD46FD92B" + }, "tags": [ { "key": "Name", @@ -228,9 +228,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -254,7 +251,10 @@ "key": "Name", "value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "constructInfo": { @@ -276,15 +276,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "tags": [ { "key": "Name", "value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "constructInfo": { @@ -317,12 +317,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "Ec2ClusterVpcPublicSubnet2RouteTable44A09188" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "Ec2ClusterVpcIGW605638EB" + }, + "routeTableId": { + "Ref": "Ec2ClusterVpcPublicSubnet2RouteTable44A09188" } } }, @@ -357,15 +357,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "Ec2ClusterVpcPublicSubnet2Subnet207D9E5E" - }, "allocationId": { "Fn::GetAtt": [ "Ec2ClusterVpcPublicSubnet2EIP921925E6", "AllocationId" ] }, + "subnetId": { + "Ref": "Ec2ClusterVpcPublicSubnet2Subnet207D9E5E" + }, "tags": [ { "key": "Name", @@ -395,9 +395,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -421,7 +418,10 @@ "key": "Name", "value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "constructInfo": { @@ -443,15 +443,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "tags": [ { "key": "Name", "value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "constructInfo": { @@ -484,12 +484,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "Ec2ClusterVpcPrivateSubnet1RouteTable50D391D1" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "Ec2ClusterVpcPublicSubnet1NATGateway79A8A839" + }, + "routeTableId": { + "Ref": "Ec2ClusterVpcPrivateSubnet1RouteTable50D391D1" } } }, @@ -514,9 +514,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -540,7 +537,10 @@ "key": "Name", "value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "constructInfo": { @@ -562,15 +562,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "tags": [ { "key": "Name", "value": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" + } } }, "constructInfo": { @@ -603,12 +603,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "Ec2ClusterVpcPrivateSubnet2RouteTable22B9DAE6" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "Ec2ClusterVpcPublicSubnet2NATGateway302F96C0" + }, + "routeTableId": { + "Ref": "Ec2ClusterVpcPrivateSubnet2RouteTable22B9DAE6" } } }, @@ -648,11 +648,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "Ec2ClusterVpc568127F1" - }, "internetGatewayId": { "Ref": "Ec2ClusterVpcIGW605638EB" + }, + "vpcId": { + "Ref": "Ec2ClusterVpc568127F1" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "Ec2ClusterDefaultAutoScalingGroupLaunchTemplate346F58BE" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole23116FA3", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicEE9E39A2": { - "id": "AllowInvoke:awssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicEE9E39A2", - "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicEE9E39A2", + "AllowInvoke:awssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook69E8851F": { + "id": "AllowInvoke:awssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook69E8851F", + "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awssfntasksecsec2integEc2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook69E8851F", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" - }, "endpoint": { "Fn::GetAtt": [ "Ec2ClusterDefaultAutoScalingGroupDrainECSHookFunctionE0DEFB31", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-sfn-tasks-ecs-ec2-integ/Ec2Cluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "Ec2ClusterDefaultAutoScalingGroupASGC5A6D4C0" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicF7263B30" + "Ref": "Ec2ClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook1AE597EF" }, "roleArn": { "Fn::GetAtt": [ @@ -2017,12 +2025,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::StepFunctions::StateMachine", "aws:cdk:cloudformation:props": { - "roleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] - }, "definitionString": { "Fn::Join": [ "", @@ -2041,6 +2043,12 @@ "\",\"TaskDefinition\":\"awssfntasksecsec2integTaskDefFAFE2BE7\",\"Overrides\":{\"ContainerOverrides\":[{\"Name\":\"TheContainer\",\"Environment\":[{\"Name\":\"SOME_KEY\",\"Value.$\":\"$.SomeKey\"}]}]},\"LaunchType\":\"EC2\"}}}}" ] ] + }, + "roleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] } } }, @@ -2090,7 +2098,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/aws-ecs-integ2.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/aws-ecs-integ2.assets.json index 832794ac26a69..3283948abc67c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/aws-ecs-integ2.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/aws-ecs-integ2.assets.json @@ -1,7 +1,7 @@ { - "version": "32.0.0", + "version": "36.0.0", "files": { - "c3be3861b160a5c4b786a665bc563d4af7f3789d729e9568e720d7e14d398b6c": { + "3ed25a4a145bd55eb88e505412559e5197f0134be307eb48c25a184fe9bef7ee": { "source": { "path": "aws-ecs-integ2.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "c3be3861b160a5c4b786a665bc563d4af7f3789d729e9568e720d7e14d398b6c.json", + "objectKey": "3ed25a4a145bd55eb88e505412559e5197f0134be307eb48c25a184fe9bef7ee.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/aws-ecs-integ2.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/aws-ecs-integ2.template.json index f5dd2baccaa15..e080b0ce22696 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/aws-ecs-integ2.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/aws-ecs-integ2.template.json @@ -21,9 +21,6 @@ "FargateClusterVpcPublicSubnet1SubnetB9C24BC7": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -47,21 +44,24 @@ "Key": "Name", "Value": "aws-ecs-integ2/FargateCluster/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "FargateClusterVpcPublicSubnet1RouteTable1D7FA747": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ2/FargateCluster/Vpc/PublicSubnet1" } - ] + ], + "VpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "FargateClusterVpcPublicSubnet1RouteTableAssociation80F1442F": { @@ -78,12 +78,12 @@ "FargateClusterVpcPublicSubnet1DefaultRoute80086690": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "FargateClusterVpcPublicSubnet1RouteTable1D7FA747" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "FargateClusterVpcIGW827638CB" + }, + "RouteTableId": { + "Ref": "FargateClusterVpcPublicSubnet1RouteTable1D7FA747" } }, "DependsOn": [ @@ -105,15 +105,15 @@ "FargateClusterVpcPublicSubnet1NATGateway5202D86A": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "FargateClusterVpcPublicSubnet1SubnetB9C24BC7" - }, "AllocationId": { "Fn::GetAtt": [ "FargateClusterVpcPublicSubnet1EIPF91909D0", "AllocationId" ] }, + "SubnetId": { + "Ref": "FargateClusterVpcPublicSubnet1SubnetB9C24BC7" + }, "Tags": [ { "Key": "Name", @@ -129,9 +129,6 @@ "FargateClusterVpcPublicSubnet2Subnet24C0F9D8": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -155,21 +152,24 @@ "Key": "Name", "Value": "aws-ecs-integ2/FargateCluster/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "FargateClusterVpcPublicSubnet2RouteTable1493C5D6": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ2/FargateCluster/Vpc/PublicSubnet2" } - ] + ], + "VpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "FargateClusterVpcPublicSubnet2RouteTableAssociation3EFA74DC": { @@ -186,12 +186,12 @@ "FargateClusterVpcPublicSubnet2DefaultRoute8E847CD2": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "FargateClusterVpcPublicSubnet2RouteTable1493C5D6" - }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "FargateClusterVpcIGW827638CB" + }, + "RouteTableId": { + "Ref": "FargateClusterVpcPublicSubnet2RouteTable1493C5D6" } }, "DependsOn": [ @@ -213,15 +213,15 @@ "FargateClusterVpcPublicSubnet2NATGatewayFFEC8ED2": { "Type": "AWS::EC2::NatGateway", "Properties": { - "SubnetId": { - "Ref": "FargateClusterVpcPublicSubnet2Subnet24C0F9D8" - }, "AllocationId": { "Fn::GetAtt": [ "FargateClusterVpcPublicSubnet2EIPBBB24774", "AllocationId" ] }, + "SubnetId": { + "Ref": "FargateClusterVpcPublicSubnet2Subnet24C0F9D8" + }, "Tags": [ { "Key": "Name", @@ -237,9 +237,6 @@ "FargateClusterVpcPrivateSubnet1Subnet9127625F": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "AvailabilityZone": { "Fn::Select": [ 0, @@ -263,21 +260,24 @@ "Key": "Name", "Value": "aws-ecs-integ2/FargateCluster/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "FargateClusterVpcPrivateSubnet1RouteTable21B3CEAE": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ2/FargateCluster/Vpc/PrivateSubnet1" } - ] + ], + "VpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "FargateClusterVpcPrivateSubnet1RouteTableAssociation78F6E213": { @@ -294,21 +294,18 @@ "FargateClusterVpcPrivateSubnet1DefaultRoute0438DCBA": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "FargateClusterVpcPrivateSubnet1RouteTable21B3CEAE" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "FargateClusterVpcPublicSubnet1NATGateway5202D86A" + }, + "RouteTableId": { + "Ref": "FargateClusterVpcPrivateSubnet1RouteTable21B3CEAE" } } }, "FargateClusterVpcPrivateSubnet2Subnet307CEE57": { "Type": "AWS::EC2::Subnet", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "AvailabilityZone": { "Fn::Select": [ 1, @@ -332,21 +329,24 @@ "Key": "Name", "Value": "aws-ecs-integ2/FargateCluster/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "FargateClusterVpcPrivateSubnet2RouteTable7B7F9678": { "Type": "AWS::EC2::RouteTable", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "Tags": [ { "Key": "Name", "Value": "aws-ecs-integ2/FargateCluster/Vpc/PrivateSubnet2" } - ] + ], + "VpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "FargateClusterVpcPrivateSubnet2RouteTableAssociation3A46964C": { @@ -363,12 +363,12 @@ "FargateClusterVpcPrivateSubnet2DefaultRoute35FDD29D": { "Type": "AWS::EC2::Route", "Properties": { - "RouteTableId": { - "Ref": "FargateClusterVpcPrivateSubnet2RouteTable7B7F9678" - }, "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": { "Ref": "FargateClusterVpcPublicSubnet2NATGatewayFFEC8ED2" + }, + "RouteTableId": { + "Ref": "FargateClusterVpcPrivateSubnet2RouteTable7B7F9678" } } }, @@ -386,11 +386,11 @@ "FargateClusterVpcVPCGW38717255": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { - "VpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "InternetGatewayId": { "Ref": "FargateClusterVpcIGW827638CB" + }, + "VpcId": { + "Ref": "FargateClusterVpc377E8024" } } }, @@ -589,8 +589,6 @@ "FargateClusterDefaultAutoScalingGroupASG36A4948F": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { - "MaxSize": "1", - "MinSize": "1", "LaunchTemplate": { "LaunchTemplateId": { "Ref": "FargateClusterDefaultAutoScalingGroupLaunchTemplate7BE88B5A" @@ -602,6 +600,8 @@ ] } }, + "MaxSize": "1", + "MinSize": "1", "Tags": [ { "Key": "Name", @@ -757,12 +757,6 @@ "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" }, - "Role": { - "Fn::GetAtt": [ - "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole7FEDCD32", - "Arn" - ] - }, "Environment": { "Variables": { "CLUSTER": { @@ -771,6 +765,12 @@ } }, "Handler": "index.lambda_handler", + "Role": { + "Fn::GetAtt": [ + "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole7FEDCD32", + "Arn" + ] + }, "Runtime": "python3.9", "Tags": [ { @@ -785,7 +785,7 @@ "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole7FEDCD32" ] }, - "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic9C6EC468C75B1F21": { + "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookD9134A819A1EFA59": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", @@ -797,26 +797,26 @@ }, "Principal": "sns.amazonaws.com", "SourceArn": { - "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" + "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" } } }, - "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic37856E82": { + "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHookE946F86E": { "Type": "AWS::SNS::Subscription", "Properties": { - "Protocol": "lambda", - "TopicArn": { - "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" - }, "Endpoint": { "Fn::GetAtt": [ "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionE3D5BEE8", "Arn" ] + }, + "Protocol": "lambda", + "TopicArn": { + "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" } } }, - "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10": { + "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE": { "Type": "AWS::SNS::Topic", "Properties": { "Tags": [ @@ -859,7 +859,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" + "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" } } ], @@ -879,11 +879,11 @@ "AutoScalingGroupName": { "Ref": "FargateClusterDefaultAutoScalingGroupASG36A4948F" }, - "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "DefaultResult": "CONTINUE", "HeartbeatTimeout": 300, + "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "NotificationTargetARN": { - "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" + "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" }, "RoleARN": { "Fn::GetAtt": [ @@ -1142,12 +1142,6 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { - "RoleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] - }, "DefinitionString": { "Fn::Join": [ "", @@ -1170,6 +1164,12 @@ ":states:::ecs:runTask.sync\"}}}" ] ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] } }, "DependsOn": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/cdk.out index f0b901e7c06e5..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"32.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/integ.json index 51d28abadfeea..1da6b884b5beb 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "testCases": { "integ.ec2-task": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/manifest.json index 23cdcdb67e8b2..ad2318f21a523 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "32.0.0", + "version": "36.0.0", "artifacts": { "aws-ecs-integ2.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-ecs-integ2.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}/c3be3861b160a5c4b786a665bc563d4af7f3789d729e9568e720d7e14d398b6c.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/3ed25a4a145bd55eb88e505412559e5197f0134be307eb48c25a184fe9bef7ee.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -231,22 +232,22 @@ "data": "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionE3D5BEE8" } ], - "/aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic9C6EC468": [ + "/aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookD9134A81": [ { "type": "aws:cdk:logicalId", - "data": "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic9C6EC468C75B1F21" + "data": "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookD9134A819A1EFA59" } ], - "/aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource": [ + "/aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic37856E82" + "data": "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionTopicLifecycleHookDrainHookE946F86E" } ], - "/aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource": [ + "/aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource": [ { "type": "aws:cdk:logicalId", - "data": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" + "data": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" } ], "/aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource": [ @@ -333,10 +334,28 @@ "data": "CheckBootstrapVersion" } ], - "FargateClusterDefaultAutoScalingGroupLaunchTemplateProfile7159126B": [ + "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic9C6EC468C75B1F21": [ { "type": "aws:cdk:logicalId", - "data": "FargateClusterDefaultAutoScalingGroupLaunchTemplateProfile7159126B", + "data": "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionAllowInvokeawsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic9C6EC468C75B1F21", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic37856E82": [ + { + "type": "aws:cdk:logicalId", + "data": "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionTopic37856E82", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10": [ + { + "type": "aws:cdk:logicalId", + "data": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/tree.json index 10a6719d7200e..21d7abe79e3a5 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions-tasks/test/ecs/integ.ec2-task.js.snapshot/tree.json @@ -61,9 +61,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -87,7 +84,10 @@ "key": "Name", "value": "aws-ecs-integ2/FargateCluster/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "constructInfo": { @@ -109,15 +109,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ2/FargateCluster/Vpc/PublicSubnet1" } - ] + ], + "vpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "constructInfo": { @@ -150,12 +150,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "FargateClusterVpcPublicSubnet1RouteTable1D7FA747" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "FargateClusterVpcIGW827638CB" + }, + "routeTableId": { + "Ref": "FargateClusterVpcPublicSubnet1RouteTable1D7FA747" } } }, @@ -190,15 +190,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "FargateClusterVpcPublicSubnet1SubnetB9C24BC7" - }, "allocationId": { "Fn::GetAtt": [ "FargateClusterVpcPublicSubnet1EIPF91909D0", "AllocationId" ] }, + "subnetId": { + "Ref": "FargateClusterVpcPublicSubnet1SubnetB9C24BC7" + }, "tags": [ { "key": "Name", @@ -228,9 +228,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -254,7 +251,10 @@ "key": "Name", "value": "aws-ecs-integ2/FargateCluster/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "constructInfo": { @@ -276,15 +276,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ2/FargateCluster/Vpc/PublicSubnet2" } - ] + ], + "vpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "constructInfo": { @@ -317,12 +317,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "FargateClusterVpcPublicSubnet2RouteTable1493C5D6" - }, "destinationCidrBlock": "0.0.0.0/0", "gatewayId": { "Ref": "FargateClusterVpcIGW827638CB" + }, + "routeTableId": { + "Ref": "FargateClusterVpcPublicSubnet2RouteTable1493C5D6" } } }, @@ -357,15 +357,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { - "subnetId": { - "Ref": "FargateClusterVpcPublicSubnet2Subnet24C0F9D8" - }, "allocationId": { "Fn::GetAtt": [ "FargateClusterVpcPublicSubnet2EIPBBB24774", "AllocationId" ] }, + "subnetId": { + "Ref": "FargateClusterVpcPublicSubnet2Subnet24C0F9D8" + }, "tags": [ { "key": "Name", @@ -395,9 +395,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "availabilityZone": { "Fn::Select": [ 0, @@ -421,7 +418,10 @@ "key": "Name", "value": "aws-ecs-integ2/FargateCluster/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "constructInfo": { @@ -443,15 +443,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ2/FargateCluster/Vpc/PrivateSubnet1" } - ] + ], + "vpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "constructInfo": { @@ -484,12 +484,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "FargateClusterVpcPrivateSubnet1RouteTable21B3CEAE" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "FargateClusterVpcPublicSubnet1NATGateway5202D86A" + }, + "routeTableId": { + "Ref": "FargateClusterVpcPrivateSubnet1RouteTable21B3CEAE" } } }, @@ -514,9 +514,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "availabilityZone": { "Fn::Select": [ 1, @@ -540,7 +537,10 @@ "key": "Name", "value": "aws-ecs-integ2/FargateCluster/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "constructInfo": { @@ -562,15 +562,15 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "tags": [ { "key": "Name", "value": "aws-ecs-integ2/FargateCluster/Vpc/PrivateSubnet2" } - ] + ], + "vpcId": { + "Ref": "FargateClusterVpc377E8024" + } } }, "constructInfo": { @@ -603,12 +603,12 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "FargateClusterVpcPrivateSubnet2RouteTable7B7F9678" - }, "destinationCidrBlock": "0.0.0.0/0", "natGatewayId": { "Ref": "FargateClusterVpcPublicSubnet2NATGatewayFFEC8ED2" + }, + "routeTableId": { + "Ref": "FargateClusterVpcPrivateSubnet2RouteTable7B7F9678" } } }, @@ -648,11 +648,11 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { - "vpcId": { - "Ref": "FargateClusterVpc377E8024" - }, "internetGatewayId": { "Ref": "FargateClusterVpcIGW827638CB" + }, + "vpcId": { + "Ref": "FargateClusterVpc377E8024" } } }, @@ -854,6 +854,14 @@ "version": "0.0.0" } }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/ImportedInstanceProfile", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "LaunchTemplate": { "id": "LaunchTemplate", "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LaunchTemplate", @@ -953,8 +961,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", "aws:cdk:cloudformation:props": { - "maxSize": "1", - "minSize": "1", "launchTemplate": { "launchTemplateId": { "Ref": "FargateClusterDefaultAutoScalingGroupLaunchTemplate7BE88B5A" @@ -966,6 +972,8 @@ ] } }, + "maxSize": "1", + "minSize": "1", "tags": [ { "key": "Name", @@ -1173,12 +1181,6 @@ "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" }, - "role": { - "Fn::GetAtt": [ - "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole7FEDCD32", - "Arn" - ] - }, "environment": { "variables": { "CLUSTER": { @@ -1187,6 +1189,12 @@ } }, "handler": "index.lambda_handler", + "role": { + "Fn::GetAtt": [ + "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionServiceRole7FEDCD32", + "Arn" + ] + }, "runtime": "python3.9", "tags": [ { @@ -1202,9 +1210,9 @@ "version": "0.0.0" } }, - "AllowInvoke:awsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic9C6EC468": { - "id": "AllowInvoke:awsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic9C6EC468", - "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic9C6EC468", + "AllowInvoke:awsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookD9134A81": { + "id": "AllowInvoke:awsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookD9134A81", + "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/AllowInvoke:awsecsinteg2FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookD9134A81", "attributes": { "aws:cdk:cloudformation:type": "AWS::Lambda::Permission", "aws:cdk:cloudformation:props": { @@ -1217,7 +1225,7 @@ }, "principal": "sns.amazonaws.com", "sourceArn": { - "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" + "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" } } }, @@ -1226,25 +1234,25 @@ "version": "0.0.0" } }, - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/Topic/Resource", + "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/DrainECSHook/Function/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Subscription", "aws:cdk:cloudformation:props": { - "protocol": "lambda", - "topicArn": { - "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" - }, "endpoint": { "Fn::GetAtt": [ "FargateClusterDefaultAutoScalingGroupDrainECSHookFunctionE3D5BEE8", "Arn" ] + }, + "protocol": "lambda", + "topicArn": { + "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" } } }, @@ -1268,20 +1276,20 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } }, "LifecycleHookDrainHook": { "id": "LifecycleHookDrainHook", "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook", "children": { - "Topic": { - "id": "Topic", - "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic", + "TopicLifecycleHookDrainHook": { + "id": "TopicLifecycleHookDrainHook", + "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook", "children": { "Resource": { "id": "Resource", - "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Topic/Resource", + "path": "aws-ecs-integ2/FargateCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/TopicLifecycleHookDrainHook/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::SNS::Topic", "aws:cdk:cloudformation:props": { @@ -1363,7 +1371,7 @@ "Action": "sns:Publish", "Effect": "Allow", "Resource": { - "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" + "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" } } ], @@ -1403,11 +1411,11 @@ "autoScalingGroupName": { "Ref": "FargateClusterDefaultAutoScalingGroupASG36A4948F" }, - "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "defaultResult": "CONTINUE", "heartbeatTimeout": 300, + "lifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING", "notificationTargetArn": { - "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopic49146C10" + "Ref": "FargateClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHookDDF708CE" }, "roleArn": { "Fn::GetAtt": [ @@ -1909,12 +1917,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::StepFunctions::StateMachine", "aws:cdk:cloudformation:props": { - "roleArn": { - "Fn::GetAtt": [ - "StateMachineRoleB840431D", - "Arn" - ] - }, "definitionString": { "Fn::Join": [ "", @@ -1937,6 +1939,12 @@ ":states:::ecs:runTask.sync\"}}}" ] ] + }, + "roleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] } } }, @@ -1978,7 +1986,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.55" + "version": "10.3.0" } } }, diff --git a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/lambda-hook.ts b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/lambda-hook.ts index b280eee97971d..07865a686fe1b 100644 --- a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/lambda-hook.ts +++ b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/lambda-hook.ts @@ -24,8 +24,8 @@ export class FunctionHook implements autoscaling.ILifecycleHookTarget { * If the `IRole` does not exist in `options`, will create an `IRole` and an SNS Topic and attach both to the lifecycle hook. * If the `IRole` does exist in `options`, will only create an SNS Topic and attach it to the lifecycle hook. */ - public bind(_scope: Construct, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { - const topic = new sns.Topic(_scope, 'Topic', { + public bind(_scope: Construct, _id: string, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { + const topic = new sns.Topic(_scope, `Topic${_id}`, { masterKey: this.encryptionKey, }); @@ -37,6 +37,6 @@ export class FunctionHook implements autoscaling.ILifecycleHookTarget { // are in place. this.encryptionKey?.grant(role, 'kms:Decrypt', 'kms:GenerateDataKey'); topic.addSubscription(new subs.LambdaSubscription(this.fn)); - return new TopicHook(topic).bind(_scope, { lifecycleHook: options.lifecycleHook, role }); + return new TopicHook(topic).bind(_scope, _id, { lifecycleHook: options.lifecycleHook, role }); } } diff --git a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/queue-hook.ts b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/queue-hook.ts index 2b034604362f6..7c6524589fdea 100644 --- a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/queue-hook.ts +++ b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/queue-hook.ts @@ -16,7 +16,7 @@ export class QueueHook implements autoscaling.ILifecycleHookTarget { * * @returns the `IRole` with access to send messages and the ARN of the queue it has access to send messages to. */ - public bind(_scope: Construct, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { + public bind(_scope: Construct, _id: string, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { const role = createRole(_scope, options.role); this.queue.grantSendMessages(role); diff --git a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/topic-hook.ts b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/topic-hook.ts index bb3fc5bf32417..3dcf00e9bcfb0 100644 --- a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/topic-hook.ts +++ b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/lib/topic-hook.ts @@ -16,7 +16,7 @@ export class TopicHook implements autoscaling.ILifecycleHookTarget { * * @returns the `IRole` with topic publishing permissions and the ARN of the topic it has publishing permission to. */ - public bind(_scope: Construct, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { + public bind(_scope: Construct, _id: string, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { const role = createRole(_scope, options.role); this.topic.grantPublish(role); diff --git a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/test/hooks.test.ts b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/test/hooks.test.ts index 60e59fd9337bf..5064da2a1e9e3 100644 --- a/packages/aws-cdk-lib/aws-autoscaling-hooktargets/test/hooks.test.ts +++ b/packages/aws-cdk-lib/aws-autoscaling-hooktargets/test/hooks.test.ts @@ -131,10 +131,10 @@ describe('given an AutoScalingGroup and no role', () => { }); // THEN - Template.fromStack(stack).hasResourceProperties('AWS::AutoScaling::LifecycleHook', { NotificationTargetARN: { Ref: 'ASGLifecycleHookTransTopic9B0D4842' } }); + Template.fromStack(stack).hasResourceProperties('AWS::AutoScaling::LifecycleHook', { NotificationTargetARN: { Ref: 'ASGLifecycleHookTransTopicLifecycleHookTrans97629BD2' } }); Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { Protocol: 'lambda', - TopicArn: { Ref: 'ASGLifecycleHookTransTopic9B0D4842' }, + TopicArn: { Ref: 'ASGLifecycleHookTransTopicLifecycleHookTrans97629BD2' }, Endpoint: { 'Fn::GetAtt': ['Fn9270CBC0', 'Arn'] }, }); Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { @@ -144,7 +144,7 @@ describe('given an AutoScalingGroup and no role', () => { Action: 'sns:Publish', Effect: 'Allow', Resource: { - Ref: 'ASGLifecycleHookTransTopic9B0D4842', + Ref: 'ASGLifecycleHookTransTopicLifecycleHookTrans97629BD2', }, }, ], @@ -311,10 +311,10 @@ describe('given an AutoScalingGroup and a role', () => { }); // THEN - Template.fromStack(stack).hasResourceProperties('AWS::AutoScaling::LifecycleHook', { NotificationTargetARN: { Ref: 'ASGLifecycleHookTransTopic9B0D4842' } }); + Template.fromStack(stack).hasResourceProperties('AWS::AutoScaling::LifecycleHook', { NotificationTargetARN: { Ref: 'ASGLifecycleHookTransTopicLifecycleHookTrans97629BD2' } }); Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { Protocol: 'lambda', - TopicArn: { Ref: 'ASGLifecycleHookTransTopic9B0D4842' }, + TopicArn: { Ref: 'ASGLifecycleHookTransTopicLifecycleHookTrans97629BD2' }, Endpoint: { 'Fn::GetAtt': ['Fn9270CBC0', 'Arn'] }, }); Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { @@ -324,7 +324,7 @@ describe('given an AutoScalingGroup and a role', () => { Action: 'sns:Publish', Effect: 'Allow', Resource: { - Ref: 'ASGLifecycleHookTransTopic9B0D4842', + Ref: 'ASGLifecycleHookTransTopicLifecycleHookTrans97629BD2', }, }, ], diff --git a/packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook-target.ts b/packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook-target.ts index 3c255a2b61638..07eea327116cb 100644 --- a/packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook-target.ts +++ b/packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook-target.ts @@ -43,5 +43,5 @@ export interface ILifecycleHookTarget { * Called when this object is used as the target of a lifecycle hook * @param options [disable-awslint:ref-via-interface] The lifecycle hook to attach to and a role to use */ - bind(scope: constructs.Construct, options: BindHookTargetOptions): LifecycleHookTargetConfig; + bind(scope: constructs.Construct, _id: string, options: BindHookTargetOptions): LifecycleHookTargetConfig; } diff --git a/packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook.ts b/packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook.ts index d2ecb1316fcfd..af3e06cabc913 100644 --- a/packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook.ts +++ b/packages/aws-cdk-lib/aws-autoscaling/lib/lifecycle-hook.ts @@ -113,7 +113,7 @@ export class LifecycleHook extends Resource implements ILifecycleHook { physicalName: props.lifecycleHookName, }); - const targetProps = props.notificationTarget ? props.notificationTarget.bind(this, { lifecycleHook: this, role: props.role }) : undefined; + const targetProps = props.notificationTarget ? props.notificationTarget.bind(this, id, { lifecycleHook: this, role: props.role }) : undefined; if (props.role) { this._role = props.role; diff --git a/packages/aws-cdk-lib/aws-autoscaling/test/lifecyclehooks.test.ts b/packages/aws-cdk-lib/aws-autoscaling/test/lifecyclehooks.test.ts index 56dff342cc6a8..c99a01f660163 100644 --- a/packages/aws-cdk-lib/aws-autoscaling/test/lifecyclehooks.test.ts +++ b/packages/aws-cdk-lib/aws-autoscaling/test/lifecyclehooks.test.ts @@ -172,7 +172,7 @@ class FakeNotificationTarget implements autoscaling.ILifecycleHookTarget { return role; } - public bind(_scope: constructs.Construct, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { + public bind(_scope: constructs.Construct, _id: string, options: autoscaling.BindHookTargetOptions): autoscaling.LifecycleHookTargetConfig { const role = this.createRole(options.lifecycleHook, options.role); role.addToPrincipalPolicy(new iam.PolicyStatement({ diff --git a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts index 3ba6f23a71c3c..a4a88e275e461 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/cluster.test.ts @@ -415,7 +415,7 @@ describe('cluster', () => { LifecycleTransition: 'autoscaling:EC2_INSTANCE_TERMINATING', DefaultResult: 'CONTINUE', HeartbeatTimeout: 300, - NotificationTargetARN: { Ref: 'EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicACD2D4A4' }, + NotificationTargetARN: { Ref: 'EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookTopicLifecycleHookDrainHook239463CF' }, RoleARN: { 'Fn::GetAtt': ['EcsClusterDefaultAutoScalingGroupLifecycleHookDrainHookRoleA38EC83B', 'Arn'] }, });