From 6c1f7a0c4209e1fec99c7b194a455254b48bf317 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 13 May 2022 13:32:08 +0200 Subject: [PATCH 01/17] Policies for ecs_service, ecs_cluster, ecs_taskdefinition, ecs_task Signed-off-by: Alina Buzachis --- aws/policy/compute.yaml | 28 ++++++++++++++++++++++++++++ aws/terminator/compute.py | 25 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/aws/policy/compute.yaml b/aws/policy/compute.yaml index 25d404af..bbd64d64 100644 --- a/aws/policy/compute.yaml +++ b/aws/policy/compute.yaml @@ -101,6 +101,12 @@ Statement: - t3.micro - m1.large # lowest cost instance type with EBS optimization supported + - Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurFees + Effect: Allow + Action: + - ecs:CreateCluster + Resource: "*" + # ASG and ELB don't like being region restricted. - Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurNoFees Effect: Allow @@ -115,6 +121,18 @@ Statement: - elasticloadbalancing:ModifyTargetGroupAttributes - elasticloadbalancing:ModifyRule - elasticloadbalancing:SetIpAddressType + - ecs:DescribeServices + - ecs:DescribeClusters + - ecs:DescribeTaskDefinition + - ecs:ListServices + - ecs:ListClusters + - ecs:ListTagsForResource + - ecs:ListTaskDefinitions + - ecs:TagResource + - ecs:UntagResource + - ecs:PutAccountSetting + - ecs:RegisterTaskDefinition + - ecs:DeregisterTaskDefinition Resource: - "*" @@ -125,10 +143,20 @@ Statement: - ec2:CreateVolume - elasticloadbalancing:CreateLoadBalancer - elasticloadbalancing:CreateRule + - ecs:RunTask + - ecs:StartTask + - ecs:StopTask + - ecs:DeleteCluster + - ecs:CreateService + - ecs:DeleteService + - ecs:UpdateService + - ecs:UpdateCluster Resource: - 'arn:aws:ec2:{{ aws_region }}:{{ aws_account_id }}:volume/*' - 'arn:aws:elasticloadbalancing:{{ aws_region }}:{{ aws_account_id }}:*' - 'arn:aws:autoscaling:{{ aws_region }}:{{ aws_account_id }}:autoScalingGroup*' + - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:task-definition:*' + - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:cluster:*' - Sid: AllowGlobalResourceRestrictedActionsWhichIncurNoFees Effect: Allow diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index 43aaf509..be59dfa3 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -659,3 +659,28 @@ def created_time(self): def terminate(self): self.client.cancel_spot_instance_requests(SpotInstanceRequestIds=[self.id]) + +class EcsCluster(Terminator): + @staticmethod + def create(credentials): + def _paginate_cluster_results(client): + names = client.get_paginator('list_clusters').paginate( + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['clusterArns'] + + if not names: + return [] + + return [ + client.describe_clusters(name=names)['clusters'] + ] + return Terminator._create(credentials, EcsCluster, 'ecs', _paginate_cluster_results) + + @property + def name(self): + return self.instance['clusterName'] + + def terminate(self): + self.client.delete_cluster(cluster=self.name) From d4d7fdbdd7ca9a04a338d3d10cc03779b9fe7eb5 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 13 May 2022 13:34:43 +0200 Subject: [PATCH 02/17] Abstract List and Describe operations Signed-off-by: Alina Buzachis --- aws/policy/compute.yaml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/aws/policy/compute.yaml b/aws/policy/compute.yaml index bbd64d64..a0b92f37 100644 --- a/aws/policy/compute.yaml +++ b/aws/policy/compute.yaml @@ -121,13 +121,8 @@ Statement: - elasticloadbalancing:ModifyTargetGroupAttributes - elasticloadbalancing:ModifyRule - elasticloadbalancing:SetIpAddressType - - ecs:DescribeServices - - ecs:DescribeClusters - - ecs:DescribeTaskDefinition - - ecs:ListServices - - ecs:ListClusters - - ecs:ListTagsForResource - - ecs:ListTaskDefinitions + - ecs:Describe* + - ecs:List* - ecs:TagResource - ecs:UntagResource - ecs:PutAccountSetting From 6a45676e1ba23e8f48b7bd1ded9d921868838ace Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 13 May 2022 13:42:59 +0200 Subject: [PATCH 03/17] Add extra black line Signed-off-by: Alina Buzachis --- aws/terminator/compute.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index be59dfa3..c4e74c0a 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -660,6 +660,7 @@ def created_time(self): def terminate(self): self.client.cancel_spot_instance_requests(SpotInstanceRequestIds=[self.id]) + class EcsCluster(Terminator): @staticmethod def create(credentials): From bc46ca8cb00e2f244b93f4d3b70a7159f05d6f65 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 13 May 2022 14:13:11 +0200 Subject: [PATCH 04/17] Update resources Signed-off-by: Alina Buzachis --- aws/policy/compute.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/policy/compute.yaml b/aws/policy/compute.yaml index a0b92f37..5fc666b7 100644 --- a/aws/policy/compute.yaml +++ b/aws/policy/compute.yaml @@ -150,8 +150,9 @@ Statement: - 'arn:aws:ec2:{{ aws_region }}:{{ aws_account_id }}:volume/*' - 'arn:aws:elasticloadbalancing:{{ aws_region }}:{{ aws_account_id }}:*' - 'arn:aws:autoscaling:{{ aws_region }}:{{ aws_account_id }}:autoScalingGroup*' - - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:task-definition:*' - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:cluster:*' + - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:service:*' + - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:task:*' - Sid: AllowGlobalResourceRestrictedActionsWhichIncurNoFees Effect: Allow From dec38ed690a4198583bdd98e003eae55c8487d74 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 13 May 2022 15:02:40 +0200 Subject: [PATCH 05/17] Remove bracket Signed-off-by: Alina Buzachis --- aws/policy/compute.yaml | 4 +--- aws/terminator/compute.py | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/aws/policy/compute.yaml b/aws/policy/compute.yaml index 5fc666b7..38cc51ad 100644 --- a/aws/policy/compute.yaml +++ b/aws/policy/compute.yaml @@ -150,9 +150,7 @@ Statement: - 'arn:aws:ec2:{{ aws_region }}:{{ aws_account_id }}:volume/*' - 'arn:aws:elasticloadbalancing:{{ aws_region }}:{{ aws_account_id }}:*' - 'arn:aws:autoscaling:{{ aws_region }}:{{ aws_account_id }}:autoScalingGroup*' - - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:cluster:*' - - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:service:*' - - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:task:*' + - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:*' - Sid: AllowGlobalResourceRestrictedActionsWhichIncurNoFees Effect: Allow diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index c4e74c0a..54e70a22 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -674,9 +674,8 @@ def _paginate_cluster_results(client): if not names: return [] - return [ - client.describe_clusters(name=names)['clusters'] - ] + return client.describe_clusters(name=names)['clusters'] + return Terminator._create(credentials, EcsCluster, 'ecs', _paginate_cluster_results) @property From f7091879c42ab34591a04a4e621576a5d58ba680 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 13 May 2022 17:15:09 +0200 Subject: [PATCH 06/17] Update for dependant resources Signed-off-by: Alina Buzachis --- aws/terminator/compute.py | 157 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index 54e70a22..ee15284a 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -683,4 +683,161 @@ def name(self): return self.instance['clusterName'] def terminate(self): + def _paginate_task_results(cluster, container_instance): + names = self.get_paginator('list_tasks').paginate( + cluster=cluster, + containerInstance=container_instance, + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['taskArns'] + + if not names: + return [] + + return self.client.describe_taks(cluster=cluster, tasks=names)['tasks'] + + # Deregister all container instances first + names = self.client.get_paginator('list_container_instances').paginate( + cluster=self.name, + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['containerInstanceArns'] + + for name in names: + # If there are tasks running on container instances, stop them first + tasks = _paginate_task_results(cluster=self.name, containerInstance=name['containerInstanceArn']) + for task in tasks: + self.client.stop_task(cluster=self.name, task=task['taskArn']) + self.client.deregister_container_instance(cluster=self.name, containerInstance=name['containerInstanceArn']) + self.client.delete_cluster(cluster=self.name) + + +class EcsService(Terminator): + @staticmethod + def create(credentials): + def _paginate_service_results(client): + names = client.get_paginator('list_clusters').paginate( + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['clusterArns'] + + if not names: + return [] + + results = [] + clusters = client.describe_clusters(name=names)['clusters'] + for cluster in clusters: + names = client.get_paginator('list_services').paginate( + cluster=cluster, + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['serviceArns'] + + if not names: + continue + + results.append(client.describe_services(cluster=cluster, services=names)['services']) + return results + + return Terminator._create(credentials, EcsService, 'ecs', _paginate_service_results) + + @property + def name(self): + return self.instance['serviceName'] + + @property + def age_limit(self): + return datetime.timedelta(minutes=15) + + @property + def created_time(self): + return self.instance['createdAt'] + + @property + def cluster_name(self): + return self.instance['clusterArn'] + + def terminate(self): + self.client.delete_service(cluster=self.cluster_name, service=self.name, force=True) + + +class EcsContainerInstance(Terminator): + @staticmethod + def create(credentials): + def _paginate_container_instance_results(client): + names = client.get_paginator('list_clusters').paginate( + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['clusterArns'] + + if not names: + return [] + + results = [] + clusters = client.describe_clusters(name=names)['clusters'] + for cluster in clusters: + names = client.get_paginator('list_container_instances').paginate( + cluster=cluster, + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['containerInstanceArns'] + + if not names: + continue + + results.append(client.describe_container_instances(cluster=cluster, containerInstances=names)['containerInstances']) + return results + + return Terminator._create(credentials, EcsContainerInstance, 'ecs', _paginate_container_instance_results) + + @property + def name(self): + return self.instance['containerInstanceArn'] + + @property + def age_limit(self): + return datetime.timedelta(minutes=15) + + @property + def created_time(self): + return self.instance['registeredAt'] + + def terminate(self): + def _paginate_task_results(cluster, container_instance): + names = self.get_paginator('list_tasks').paginate( + cluster=cluster, + containerInstance=container_instance, + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['taskArns'] + + if not names: + return [] + + return self.client.describe_taks(cluster=cluster, tasks=names)['tasks'] + + names = self.client.get_paginator('list_clusters').paginate( + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['clusterArns'] + + if names: + clusters = self.client.describe_clusters(name=names)['clusters'] + for cluster in clusters: + # If there are tasks running on container instances, stop them first + tasks = _paginate_task_results(cluster=cluster['clusterName'], containerInstance=self.name) + for task in tasks: + self.client.stop_task(cluster=cluster['clusterName'], task=task['taskArn']) + try: + self.client.deregister_container_instance(cluster=cluster['clusterName'], containerInstance=self.name) + except botocore.exceptions.ClientError as ex: + pass From da97561d2419221bd31815645e40fb68a4a14e5a Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 13 May 2022 19:30:18 +0200 Subject: [PATCH 07/17] Refactor Signed-off-by: Alina Buzachis --- aws/terminator/compute.py | 165 +++++++------------------------------- 1 file changed, 31 insertions(+), 134 deletions(-) diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index ee15284a..926f2ff2 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -661,7 +661,7 @@ def terminate(self): self.client.cancel_spot_instance_requests(SpotInstanceRequestIds=[self.id]) -class EcsCluster(Terminator): +class Ecs(Terminator): @staticmethod def create(credentials): def _paginate_cluster_results(client): @@ -676,16 +676,16 @@ def _paginate_cluster_results(client): return client.describe_clusters(name=names)['clusters'] - return Terminator._create(credentials, EcsCluster, 'ecs', _paginate_cluster_results) + return Terminator._create(credentials, Ecs, 'ecs', _paginate_cluster_results) @property def name(self): return self.instance['clusterName'] def terminate(self): - def _paginate_task_results(cluster, container_instance): + def _paginate_task_results(container_instance): names = self.get_paginator('list_tasks').paginate( - cluster=cluster, + cluster=self.name, containerInstance=container_instance, PaginationConfig={ 'PageSize': 100, @@ -695,149 +695,46 @@ def _paginate_task_results(cluster, container_instance): if not names: return [] - return self.client.describe_taks(cluster=cluster, tasks=names)['tasks'] - - # Deregister all container instances first - names = self.client.get_paginator('list_container_instances').paginate( - cluster=self.name, - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['containerInstanceArns'] - - for name in names: - # If there are tasks running on container instances, stop them first - tasks = _paginate_task_results(cluster=self.name, containerInstance=name['containerInstanceArn']) - for task in tasks: - self.client.stop_task(cluster=self.name, task=task['taskArn']) - self.client.deregister_container_instance(cluster=self.name, containerInstance=name['containerInstanceArn']) - - self.client.delete_cluster(cluster=self.name) - - -class EcsService(Terminator): - @staticmethod - def create(credentials): - def _paginate_service_results(client): - names = client.get_paginator('list_clusters').paginate( + return self.client.describe_taks(cluster=self.name, tasks=names)['tasks'] + + def _paginate_container_instance_results(): + names = self.client.get_paginator('list_container_instances').paginate( + cluster=self.name, PaginationConfig={ 'PageSize': 100, } - ).build_full_result()['clusterArns'] + ).build_full_result()['containerInstanceArns'] if not names: return [] - - results = [] - clusters = client.describe_clusters(name=names)['clusters'] - for cluster in clusters: - names = client.get_paginator('list_services').paginate( - cluster=cluster, - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['serviceArns'] - - if not names: - continue - results.append(client.describe_services(cluster=cluster, services=names)['services']) - return results - - return Terminator._create(credentials, EcsService, 'ecs', _paginate_service_results) - - @property - def name(self): - return self.instance['serviceName'] - - @property - def age_limit(self): - return datetime.timedelta(minutes=15) - - @property - def created_time(self): - return self.instance['createdAt'] - - @property - def cluster_name(self): - return self.instance['clusterArn'] - - def terminate(self): - self.client.delete_service(cluster=self.cluster_name, service=self.name, force=True) - - -class EcsContainerInstance(Terminator): - @staticmethod - def create(credentials): - def _paginate_container_instance_results(client): - names = client.get_paginator('list_clusters').paginate( + return self.client.describe_container_instances(cluster=self.name, containerInstances=names)['containerInstances'] + + def _paginate_service_results(): + names = self.client.get_paginator('list_services').paginate( + cluster=self.name, PaginationConfig={ 'PageSize': 100, } - ).build_full_result()['clusterArns'] + ).build_full_result()['serviceArns'] if not names: return [] + + return self.client.describe_services(cluster=self.name, services=names)['services'] + + container_instances = _paginate_container_instance_results() + for name in container_instances: + # If there are tasks running on a container instance, stop them first + tasks = _paginate_task_results(cluster=self.name, containerInstance=name['containerInstanceArn']) + for task in tasks: + self.client.stop_task(cluster=self.name, task=task['taskArn']) - results = [] - clusters = client.describe_clusters(name=names)['clusters'] - for cluster in clusters: - names = client.get_paginator('list_container_instances').paginate( - cluster=cluster, - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['containerInstanceArns'] - - if not names: - continue - - results.append(client.describe_container_instances(cluster=cluster, containerInstances=names)['containerInstances']) - return results - - return Terminator._create(credentials, EcsContainerInstance, 'ecs', _paginate_container_instance_results) - - @property - def name(self): - return self.instance['containerInstanceArn'] - - @property - def age_limit(self): - return datetime.timedelta(minutes=15) - - @property - def created_time(self): - return self.instance['registeredAt'] - - def terminate(self): - def _paginate_task_results(cluster, container_instance): - names = self.get_paginator('list_tasks').paginate( - cluster=cluster, - containerInstance=container_instance, - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['taskArns'] + self.client.deregister_container_instance(containerInstance=name['containerInstanceArn']) - if not names: - return [] + # If there are running services, delete them first + services = _paginate_service_results() + for name in services: + self.client.delete_service(cluster=self.cluster_name, service=name['serviceName'], force=True) - return self.client.describe_taks(cluster=cluster, tasks=names)['tasks'] - - names = self.client.get_paginator('list_clusters').paginate( - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['clusterArns'] - - if names: - clusters = self.client.describe_clusters(name=names)['clusters'] - for cluster in clusters: - # If there are tasks running on container instances, stop them first - tasks = _paginate_task_results(cluster=cluster['clusterName'], containerInstance=self.name) - for task in tasks: - self.client.stop_task(cluster=cluster['clusterName'], task=task['taskArn']) - try: - self.client.deregister_container_instance(cluster=cluster['clusterName'], containerInstance=self.name) - except botocore.exceptions.ClientError as ex: - pass + self.client.delete_cluster(cluster=self.name) From d536503fd6d36a75c9af189a8a0b560a582d2fa0 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Mon, 16 May 2022 17:04:27 +0200 Subject: [PATCH 08/17] Remove extra space Signed-off-by: Alina Buzachis --- aws/terminator/compute.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index 926f2ff2..23bac458 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -684,7 +684,7 @@ def name(self): def terminate(self): def _paginate_task_results(container_instance): - names = self.get_paginator('list_tasks').paginate( + names = self.client.get_paginator('list_tasks').paginate( cluster=self.name, containerInstance=container_instance, PaginationConfig={ @@ -696,7 +696,7 @@ def _paginate_task_results(container_instance): return [] return self.client.describe_taks(cluster=self.name, tasks=names)['tasks'] - + def _paginate_container_instance_results(): names = self.client.get_paginator('list_container_instances').paginate( cluster=self.name, @@ -707,9 +707,9 @@ def _paginate_container_instance_results(): if not names: return [] - + return self.client.describe_container_instances(cluster=self.name, containerInstances=names)['containerInstances'] - + def _paginate_service_results(): names = self.client.get_paginator('list_services').paginate( cluster=self.name, @@ -720,13 +720,13 @@ def _paginate_service_results(): if not names: return [] - + return self.client.describe_services(cluster=self.name, services=names)['services'] - + container_instances = _paginate_container_instance_results() for name in container_instances: # If there are tasks running on a container instance, stop them first - tasks = _paginate_task_results(cluster=self.name, containerInstance=name['containerInstanceArn']) + tasks = _paginate_task_results(name['containerInstanceArn']) for task in tasks: self.client.stop_task(cluster=self.name, task=task['taskArn']) @@ -735,6 +735,6 @@ def _paginate_service_results(): # If there are running services, delete them first services = _paginate_service_results() for name in services: - self.client.delete_service(cluster=self.cluster_name, service=name['serviceName'], force=True) + self.client.delete_service(cluster=self.name, service=name['serviceName'], force=True) self.client.delete_cluster(cluster=self.name) From 04911561b41e1c45262001a7c3224fade3a3ac54 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Wed, 1 Jun 2022 15:10:03 +0200 Subject: [PATCH 09/17] apply suggestion Signed-off-by: Alina Buzachis --- aws/terminator/compute.py | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index 23bac458..15130ad1 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -662,6 +662,14 @@ def terminate(self): class Ecs(Terminator): + @property + def age_limit(self): + return datetime.timedelta(minutes=20) + + @property + def name(self): + return self.instance['clusterName'] + @staticmethod def create(credentials): def _paginate_cluster_results(client): @@ -678,10 +686,6 @@ def _paginate_cluster_results(client): return Terminator._create(credentials, Ecs, 'ecs', _paginate_cluster_results) - @property - def name(self): - return self.instance['clusterName'] - def terminate(self): def _paginate_task_results(container_instance): names = self.client.get_paginator('list_tasks').paginate( @@ -729,12 +733,31 @@ def _paginate_service_results(): tasks = _paginate_task_results(name['containerInstanceArn']) for task in tasks: self.client.stop_task(cluster=self.name, task=task['taskArn']) - - self.client.deregister_container_instance(containerInstance=name['containerInstanceArn']) - + # If there are running services, delete them first services = _paginate_service_results() for name in services: self.client.delete_service(cluster=self.name, service=name['serviceName'], force=True) + + # Deregister container instances + for name in container_instances: + self.client.deregister_container_instance(containerInstance=name['containerInstanceArn']) + + # Delete cluster + try: + self.client.delete_cluster(cluster=self.name) + except (botocore.exceptions.ClusterContainsServicesException, botocore.exceptions.ClusterContainsTasksException): + pass + +class EcsCluster(Terminator): + @property + def age_limit(self): + return datetime.timedelta(minutes=30) + + @property + def name(self): + return self.instance['clusterName'] + + def terminate(self): self.client.delete_cluster(cluster=self.name) From cd51a7e5bf8b72082732d269a056555c86cbb7c6 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Wed, 1 Jun 2022 16:22:23 +0200 Subject: [PATCH 10/17] Linting Signed-off-by: Alina Buzachis --- aws/terminator/compute.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index 15130ad1..ef5972f7 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -661,7 +661,7 @@ def terminate(self): self.client.cancel_spot_instance_requests(SpotInstanceRequestIds=[self.id]) -class Ecs(Terminator): +class Ecs(DbTerminator): @property def age_limit(self): return datetime.timedelta(minutes=20) @@ -733,24 +733,24 @@ def _paginate_service_results(): tasks = _paginate_task_results(name['containerInstanceArn']) for task in tasks: self.client.stop_task(cluster=self.name, task=task['taskArn']) - + # If there are running services, delete them first services = _paginate_service_results() for name in services: self.client.delete_service(cluster=self.name, service=name['serviceName'], force=True) - + # Deregister container instances for name in container_instances: self.client.deregister_container_instance(containerInstance=name['containerInstanceArn']) - + # Delete cluster try: self.client.delete_cluster(cluster=self.name) - except (botocore.exceptions.ClusterContainsServicesException, botocore.exceptions.ClusterContainsTasksException): + except (self.client.exceptions.ClusterContainsServicesException, self.client.exceptions.ClusterContainsTasksException): pass -class EcsCluster(Terminator): +class EcsCluster(DbTerminator): @property def age_limit(self): return datetime.timedelta(minutes=30) From ae284b42ec3c1b3a5a9869b5580cfa93748b75b5 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Tue, 7 Jun 2022 17:21:54 +0200 Subject: [PATCH 11/17] Move ecs policies and terminator classes into paas files Signed-off-by: Alina Buzachis --- aws/policy/compute.yaml | 6 -- aws/policy/paas.yaml | 33 +++++++++++ aws/terminator/compute.py | 102 -------------------------------- aws/terminator/paas.py | 120 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 108 deletions(-) diff --git a/aws/policy/compute.yaml b/aws/policy/compute.yaml index 38cc51ad..96be01d8 100644 --- a/aws/policy/compute.yaml +++ b/aws/policy/compute.yaml @@ -101,12 +101,6 @@ Statement: - t3.micro - m1.large # lowest cost instance type with EBS optimization supported - - Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurFees - Effect: Allow - Action: - - ecs:CreateCluster - Resource: "*" - # ASG and ELB don't like being region restricted. - Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurNoFees Effect: Allow diff --git a/aws/policy/paas.yaml b/aws/policy/paas.yaml index 305e910e..43fc4ee5 100644 --- a/aws/policy/paas.yaml +++ b/aws/policy/paas.yaml @@ -147,3 +147,36 @@ Statement: StringLike: lambda:FunctionArn: - arn:aws:lambda:{{ aws_region }}:{{ aws_account_id }}:function:* + + - Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurFees + Effect: Allow + Action: + - ecs:CreateCluster + Resource: "*" + + - Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurNoFees + Effect: Allow + Action: + - ecs:Describe* + - ecs:List* + - ecs:TagResource + - ecs:UntagResource + - ecs:PutAccountSetting + - ecs:RegisterTaskDefinition + - ecs:DeregisterTaskDefinition + Resource: + - "*" + + - Sid: AllowGlobalRestrictedResourceActionsWhichIncurFees + Effect: Allow + Action: + - ecs:RunTask + - ecs:StartTask + - ecs:StopTask + - ecs:DeleteCluster + - ecs:CreateService + - ecs:DeleteService + - ecs:UpdateService + - ecs:UpdateCluster + Resource: + - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:*' diff --git a/aws/terminator/compute.py b/aws/terminator/compute.py index ef5972f7..43aaf509 100644 --- a/aws/terminator/compute.py +++ b/aws/terminator/compute.py @@ -659,105 +659,3 @@ def created_time(self): def terminate(self): self.client.cancel_spot_instance_requests(SpotInstanceRequestIds=[self.id]) - - -class Ecs(DbTerminator): - @property - def age_limit(self): - return datetime.timedelta(minutes=20) - - @property - def name(self): - return self.instance['clusterName'] - - @staticmethod - def create(credentials): - def _paginate_cluster_results(client): - names = client.get_paginator('list_clusters').paginate( - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['clusterArns'] - - if not names: - return [] - - return client.describe_clusters(name=names)['clusters'] - - return Terminator._create(credentials, Ecs, 'ecs', _paginate_cluster_results) - - def terminate(self): - def _paginate_task_results(container_instance): - names = self.client.get_paginator('list_tasks').paginate( - cluster=self.name, - containerInstance=container_instance, - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['taskArns'] - - if not names: - return [] - - return self.client.describe_taks(cluster=self.name, tasks=names)['tasks'] - - def _paginate_container_instance_results(): - names = self.client.get_paginator('list_container_instances').paginate( - cluster=self.name, - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['containerInstanceArns'] - - if not names: - return [] - - return self.client.describe_container_instances(cluster=self.name, containerInstances=names)['containerInstances'] - - def _paginate_service_results(): - names = self.client.get_paginator('list_services').paginate( - cluster=self.name, - PaginationConfig={ - 'PageSize': 100, - } - ).build_full_result()['serviceArns'] - - if not names: - return [] - - return self.client.describe_services(cluster=self.name, services=names)['services'] - - container_instances = _paginate_container_instance_results() - for name in container_instances: - # If there are tasks running on a container instance, stop them first - tasks = _paginate_task_results(name['containerInstanceArn']) - for task in tasks: - self.client.stop_task(cluster=self.name, task=task['taskArn']) - - # If there are running services, delete them first - services = _paginate_service_results() - for name in services: - self.client.delete_service(cluster=self.name, service=name['serviceName'], force=True) - - # Deregister container instances - for name in container_instances: - self.client.deregister_container_instance(containerInstance=name['containerInstanceArn']) - - # Delete cluster - try: - self.client.delete_cluster(cluster=self.name) - except (self.client.exceptions.ClusterContainsServicesException, self.client.exceptions.ClusterContainsTasksException): - pass - - -class EcsCluster(DbTerminator): - @property - def age_limit(self): - return datetime.timedelta(minutes=30) - - @property - def name(self): - return self.instance['clusterName'] - - def terminate(self): - self.client.delete_cluster(cluster=self.name) diff --git a/aws/terminator/paas.py b/aws/terminator/paas.py index 5df85809..f2087493 100644 --- a/aws/terminator/paas.py +++ b/aws/terminator/paas.py @@ -1,4 +1,8 @@ +<<<<<<< HEAD from datetime import datetime +======= +import datetime +>>>>>>> ba35199 (Move ecs policies and terminator classes into paas files) from . import DbTerminator, Terminator @@ -117,3 +121,119 @@ def terminate(self): else: # delete streaming distribution self.client.delete_streaming_distribution(Id=self.Id, IfMatch=ETag) +class Ecs(DbTerminator): + @property + def age_limit(self): + return datetime.timedelta(minutes=20) + + @property + def name(self): + return self.instance['clusterName'] + + @staticmethod + def create(credentials): + def _paginate_cluster_results(client): + names = client.get_paginator('list_clusters').paginate( + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['clusterArns'] + + if not names: + return [] + + return client.describe_clusters(name=names)['clusters'] + + return Terminator._create(credentials, Ecs, 'ecs', _paginate_cluster_results) + + def terminate(self): + def _paginate_task_results(container_instance): + names = self.client.get_paginator('list_tasks').paginate( + cluster=self.name, + containerInstance=container_instance, + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['taskArns'] + + if not names: + return [] + + return self.client.describe_taks(cluster=self.name, tasks=names)['tasks'] + + def _paginate_container_instance_results(): + names = self.client.get_paginator('list_container_instances').paginate( + cluster=self.name, + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['containerInstanceArns'] + + if not names: + return [] + + return self.client.describe_container_instances(cluster=self.name, containerInstances=names)['containerInstances'] + + def _paginate_service_results(): + names = self.client.get_paginator('list_services').paginate( + cluster=self.name, + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['serviceArns'] + + if not names: + return [] + + return self.client.describe_services(cluster=self.name, services=names)['services'] + + container_instances = _paginate_container_instance_results() + for name in container_instances: + # If there are tasks running on a container instance, stop them first + tasks = _paginate_task_results(name['containerInstanceArn']) + for task in tasks: + self.client.stop_task(cluster=self.name, task=task['taskArn']) + + # If there are running services, delete them first + services = _paginate_service_results() + for name in services: + self.client.delete_service(cluster=self.name, service=name['serviceName'], force=True) + + # Deregister container instances + for name in container_instances: + self.client.deregister_container_instance(containerInstance=name['containerInstanceArn']) + + # Delete cluster + try: + self.client.delete_cluster(cluster=self.name) + except (self.client.exceptions.ClusterContainsServicesException, self.client.exceptions.ClusterContainsTasksException): + pass + + +class EcsCluster(DbTerminator): + @property + def age_limit(self): + return datetime.timedelta(minutes=30) + + @property + def name(self): + return self.instance['clusterName'] + + @staticmethod + def create(credentials): + def _paginate_cluster_results(client): + names = client.get_paginator('list_clusters').paginate( + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['clusterArns'] + + if not names: + return [] + + return client.describe_clusters(name=names)['clusters'] + + return Terminator._create(credentials, EcsCluster, 'ecs', _paginate_cluster_results) + + def terminate(self): + self.client.delete_cluster(cluster=self.name) From 19cba2cc64609491a0c4ed4ed98bfbda2cdbf31e Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 17 Jun 2022 17:31:33 +0200 Subject: [PATCH 12/17] Apply suggestion Signed-off-by: Alina Buzachis --- aws/terminator/paas.py | 66 ++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/aws/terminator/paas.py b/aws/terminator/paas.py index f2087493..9eeb3849 100644 --- a/aws/terminator/paas.py +++ b/aws/terminator/paas.py @@ -147,19 +147,31 @@ def _paginate_cluster_results(client): return Terminator._create(credentials, Ecs, 'ecs', _paginate_cluster_results) def terminate(self): - def _paginate_task_results(container_instance): - names = self.client.get_paginator('list_tasks').paginate( - cluster=self.name, - containerInstance=container_instance, - PaginationConfig={ + def _paginate_task_results(container_instance=None): + params = { + 'cluster': self.name, + 'PaginationConfig': { 'PageSize': 100, } + } + + if container_instance: + params['containerInstance'] = container_instance + + names = self.client.get_paginator('list_tasks').paginate( + **params ).build_full_result()['taskArns'] - if not names: - return [] + return [] if not names else names - return self.client.describe_taks(cluster=self.name, tasks=names)['tasks'] + def _paginate_task_definition_results(): + names = self.client.get_paginator('list_task_definitions').paginate( + PaginationConfig={ + 'PageSize': 100, + } + ).build_full_result()['taskDefinitionArns'] + + return [] if not names else names def _paginate_container_instance_results(): names = self.client.get_paginator('list_container_instances').paginate( @@ -169,10 +181,7 @@ def _paginate_container_instance_results(): } ).build_full_result()['containerInstanceArns'] - if not names: - return [] - - return self.client.describe_container_instances(cluster=self.name, containerInstances=names)['containerInstances'] + return [] if not names else names def _paginate_service_results(): names = self.client.get_paginator('list_services').paginate( @@ -182,26 +191,27 @@ def _paginate_service_results(): } ).build_full_result()['serviceArns'] - if not names: - return [] - - return self.client.describe_services(cluster=self.name, services=names)['services'] - - container_instances = _paginate_container_instance_results() - for name in container_instances: - # If there are tasks running on a container instance, stop them first - tasks = _paginate_task_results(name['containerInstanceArn']) - for task in tasks: - self.client.stop_task(cluster=self.name, task=task['taskArn']) + return [] if not names else names # If there are running services, delete them first services = _paginate_service_results() - for name in services: - self.client.delete_service(cluster=self.name, service=name['serviceName'], force=True) + for each in services: + self.client.delete_service(cluster=self.name, service=each, force=True) - # Deregister container instances - for name in container_instances: - self.client.deregister_container_instance(containerInstance=name['containerInstanceArn']) + # Deregister container instances and stop any running task + container_instances = _paginate_container_instance_results() + for each in container_instances: + self.client.deregister_container_instance(containerInstance=each['containerInstanceArn'], force=True) + + # Deregister task definitions + task_definitions = _paginate_task_definition_results() + for each in task_definitions: + self.client.deregister_task_definition(taskDefinition=each) + + # Stop all the tasks + tasks = _paginate_task_results() + for each in tasks: + self.client.stop_task(cluster=self.name, task=each) # Delete cluster try: From 37706aaf048b487d02e57f60ccfb64922ec4038e Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Mon, 4 Jul 2022 15:27:36 +0200 Subject: [PATCH 13/17] Apply suggestion Signed-off-by: Alina Buzachis --- aws/terminator/paas.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/terminator/paas.py b/aws/terminator/paas.py index 9eeb3849..090201b9 100644 --- a/aws/terminator/paas.py +++ b/aws/terminator/paas.py @@ -142,7 +142,7 @@ def _paginate_cluster_results(client): if not names: return [] - return client.describe_clusters(name=names)['clusters'] + return client.describe_clusters(clusters=names)['clusters'] return Terminator._create(credentials, Ecs, 'ecs', _paginate_cluster_results) @@ -241,7 +241,7 @@ def _paginate_cluster_results(client): if not names: return [] - return client.describe_clusters(name=names)['clusters'] + return client.describe_clusters(clusters=names)['clusters'] return Terminator._create(credentials, EcsCluster, 'ecs', _paginate_cluster_results) From 909c74624aa08a8f82c2d885a4ac54670cb80b5c Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 3 Feb 2023 12:37:20 +0100 Subject: [PATCH 14/17] Fix rebase Signed-off-by: Alina Buzachis --- aws/policy/compute.yaml | 16 ---------------- aws/terminator/paas.py | 6 ++---- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/aws/policy/compute.yaml b/aws/policy/compute.yaml index 96be01d8..25d404af 100644 --- a/aws/policy/compute.yaml +++ b/aws/policy/compute.yaml @@ -115,13 +115,6 @@ Statement: - elasticloadbalancing:ModifyTargetGroupAttributes - elasticloadbalancing:ModifyRule - elasticloadbalancing:SetIpAddressType - - ecs:Describe* - - ecs:List* - - ecs:TagResource - - ecs:UntagResource - - ecs:PutAccountSetting - - ecs:RegisterTaskDefinition - - ecs:DeregisterTaskDefinition Resource: - "*" @@ -132,19 +125,10 @@ Statement: - ec2:CreateVolume - elasticloadbalancing:CreateLoadBalancer - elasticloadbalancing:CreateRule - - ecs:RunTask - - ecs:StartTask - - ecs:StopTask - - ecs:DeleteCluster - - ecs:CreateService - - ecs:DeleteService - - ecs:UpdateService - - ecs:UpdateCluster Resource: - 'arn:aws:ec2:{{ aws_region }}:{{ aws_account_id }}:volume/*' - 'arn:aws:elasticloadbalancing:{{ aws_region }}:{{ aws_account_id }}:*' - 'arn:aws:autoscaling:{{ aws_region }}:{{ aws_account_id }}:autoScalingGroup*' - - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:*' - Sid: AllowGlobalResourceRestrictedActionsWhichIncurNoFees Effect: Allow diff --git a/aws/terminator/paas.py b/aws/terminator/paas.py index 090201b9..b59f30a2 100644 --- a/aws/terminator/paas.py +++ b/aws/terminator/paas.py @@ -1,8 +1,4 @@ -<<<<<<< HEAD from datetime import datetime -======= -import datetime ->>>>>>> ba35199 (Move ecs policies and terminator classes into paas files) from . import DbTerminator, Terminator @@ -121,6 +117,8 @@ def terminate(self): else: # delete streaming distribution self.client.delete_streaming_distribution(Id=self.Id, IfMatch=ETag) + + class Ecs(DbTerminator): @property def age_limit(self): From c15a87aaa339dbe9567b11f55e8628bc0242e986 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Fri, 3 Feb 2023 12:42:53 +0100 Subject: [PATCH 15/17] remove trailing spaces Signed-off-by: Alina Buzachis --- aws/policy/paas.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/policy/paas.yaml b/aws/policy/paas.yaml index 43fc4ee5..3e0c7d2a 100644 --- a/aws/policy/paas.yaml +++ b/aws/policy/paas.yaml @@ -147,13 +147,13 @@ Statement: StringLike: lambda:FunctionArn: - arn:aws:lambda:{{ aws_region }}:{{ aws_account_id }}:function:* - + - Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurFees Effect: Allow Action: - ecs:CreateCluster Resource: "*" - + - Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurNoFees Effect: Allow Action: @@ -166,7 +166,7 @@ Statement: - ecs:DeregisterTaskDefinition Resource: - "*" - + - Sid: AllowGlobalRestrictedResourceActionsWhichIncurFees Effect: Allow Action: From 081403ee4288e29b04c8eedb0ec308bd626fbb08 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Thu, 16 Feb 2023 15:25:47 +0100 Subject: [PATCH 16/17] More ECS related permissions --- aws/policy/paas.yaml | 2 ++ aws/policy/security-services.yaml | 18 ++++++------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/aws/policy/paas.yaml b/aws/policy/paas.yaml index 3e0c7d2a..8fdea1f6 100644 --- a/aws/policy/paas.yaml +++ b/aws/policy/paas.yaml @@ -178,5 +178,7 @@ Statement: - ecs:DeleteService - ecs:UpdateService - ecs:UpdateCluster + - ecs:*CapacityProvider + - ecs:PutClusterCapacityProviders Resource: - 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:*' diff --git a/aws/policy/security-services.yaml b/aws/policy/security-services.yaml index 9d07e30f..35769269 100644 --- a/aws/policy/security-services.yaml +++ b/aws/policy/security-services.yaml @@ -31,6 +31,7 @@ Statement: - 'arn:aws:iam::aws:policy/service-role/AmazonDMSVPCManagementRole' - 'arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole' - 'arn:aws:iam::aws:policy/service-role/AWSServiceRoleForVPCTransitGateway' + - 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole' # Legacy - We need to backport ansible-collections/community.aws/63 or # wait until community.aws drops CI support for Ansible 2.9 @@ -73,12 +74,7 @@ Statement: Action: - access-analyzer:ValidatePolicy - iam:GetRole - - iam:ListAttachedRolePolicies - - iam:ListRoles - - iam:ListRolePolicies - - iam:ListRoleTags - - iam:ListSAMLProviders - - iam:ListServerCertificates + - iam:List* - iam:TagRole - iam:UntagRole - kms:CreateAlias @@ -92,12 +88,7 @@ Statement: - kms:GetKeyPolicy - kms:GetKeyRotationStatus - kms:GetPublicKey - - kms:ListAliases - - kms:ListGrants - - kms:ListKeyPolicies - - kms:ListKeys - - kms:ListResourceTags - - kms:ListRetirableGrants + - kms:List* - kms:PutKeyPolicy - kms:RetireGrant - kms:ScheduleKeyDeletion @@ -181,6 +172,7 @@ Statement: - 'arn:aws:iam::{{ aws_account_id }}:role/rds_export_task' - 'arn:aws:logs:{{ aws_region }}:{{ aws_account_id }}:log-group:*' - 'arn:aws:logs:{{ aws_region }}:{{ aws_account_id }}:log-group:ansible-test*' + - 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS' # This allows AWS Services to autmatically create their Default Service Linked Roles # These have fixed policies and can only be assumed by the service itself. @@ -195,6 +187,7 @@ Statement: - 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/eks-nodegroup.amazonaws.com/*' - 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/transitgateway.amazonaws.com/*' - 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/network-firewall.amazonaws.com/*' + - 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/ecs.amazonaws.com/*' Condition: ForAnyValue:StringEquals: iam:AWSServiceName: @@ -204,3 +197,4 @@ Statement: - 'eks-nodegroup.amazonaws.com' - 'transitgateway.amazonaws.com' - 'network-firewall.amazonaws.com' + - 'ecs.amazonaws.com' From 378c49ca8ba81e31b226f43a36d42f1651f80a18 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Wed, 22 Feb 2023 12:08:10 +0100 Subject: [PATCH 17/17] requested changes --- aws/policy/security-services.yaml | 16 ++-------------- aws/terminator/paas.py | 4 ++-- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/aws/policy/security-services.yaml b/aws/policy/security-services.yaml index 35769269..3f413719 100644 --- a/aws/policy/security-services.yaml +++ b/aws/policy/security-services.yaml @@ -31,23 +31,11 @@ Statement: - 'arn:aws:iam::aws:policy/service-role/AmazonDMSVPCManagementRole' - 'arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole' - 'arn:aws:iam::aws:policy/service-role/AWSServiceRoleForVPCTransitGateway' - - 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole' - - # Legacy - We need to backport ansible-collections/community.aws/63 or - # wait until community.aws drops CI support for Ansible 2.9 - - Sid: AllowPassRole - Effect: Allow - Action: - - iam:PassRole - Resource: - - 'arn:aws:iam::{{ aws_account_id }}:role/ansible_lambda_role' + - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy' - Sid: AllowRegionalUnrestrictedResourceActionsWhichIncurNoFees Effect: Allow Action: - - iam:ListAccountAliases - - iam:ListPolicies - - iam:ListInstanceProfiles - iam:GetUser - acm:ListCertificates - acm:ListTagsForCertificate @@ -143,7 +131,6 @@ Statement: - iam:GetInstanceProfile - iam:GetSAMLProvider - iam:GetServerCertificate - - iam:ListInstanceProfilesForRole - iam:PassRole - iam:RemoveRoleFromInstanceProfile - iam:UpdateSAMLProvider @@ -198,3 +185,4 @@ Statement: - 'transitgateway.amazonaws.com' - 'network-firewall.amazonaws.com' - 'ecs.amazonaws.com' + - 'ecs-test.amazonaws.com' diff --git a/aws/terminator/paas.py b/aws/terminator/paas.py index b59f30a2..02053ba3 100644 --- a/aws/terminator/paas.py +++ b/aws/terminator/paas.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timedelta from . import DbTerminator, Terminator @@ -221,7 +221,7 @@ def _paginate_service_results(): class EcsCluster(DbTerminator): @property def age_limit(self): - return datetime.timedelta(minutes=30) + return timedelta(minutes=30) @property def name(self):