diff --git a/plugins/modules/ecs_service_info.py b/plugins/modules/ecs_service_info.py index 02a6abff207..fc4a5cff570 100644 --- a/plugins/modules/ecs_service_info.py +++ b/plugins/modules/ecs_service_info.py @@ -29,12 +29,13 @@ type: bool cluster: description: - - The cluster ARNS in which to list the services. + - The cluster ARNS in which to list the services. If not provided, all clusters are listed. required: false - type: str + type: list + elements: str service: description: - - One or more services to get details for + - One or more services to get details for. If not provided, all services are listed. required: false type: list elements: str @@ -55,9 +56,15 @@ details: true register: output -# Basic listing example +# Basic listing example for all services in all clusters - community.aws.ecs_service_info: - cluster: test-cluster + details: true + register: output +# Basic listing example for the list of services in two specific clusters +- community.aws.ecs_service_info: + cluster: + - test-cluster + - prod-cluster register: output """ @@ -161,6 +168,16 @@ def list_services_with_backoff(self, **kwargs): def describe_services_with_backoff(self, **kwargs): return self.ecs.describe_services(**kwargs) + def list_clusters(self): + try: + paginator = self.ecs.get_paginator("list_clusters") + response = paginator.paginate().build_full_result() + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + self.module.fail_json_aws(e, msg="Couldn't list ECS clusters") + # Note that the clusters list can be emptu if there are no clusters (and thus no services) + clusters = list(response["clusterArns"]) + return clusters + def list_services(self, cluster): fn_args = dict() if cluster and cluster is not None: @@ -203,6 +220,26 @@ def extract_service_from(self, service): e["createdAt"] = str(e["createdAt"]) return service + def get_cluster_services(self): + if self.module.params["cluster"]: + clusters = self.module.params["cluster"] + else: + clusters = self.list_clusters() + + cluster_services = {} + for cluster in clusters: + service_arns = self.list_services(cluster)["services"] + if self.module.params["service"]: + service_names = [service.split("/")[-1] for service in service_arns] + services_found = [] + for service in self.module.params["service"]: + if service in service_names or service in service_arns: + services_found.append(service) + cluster_services[cluster] = services_found + else: + cluster_services[cluster] = service_arns + return cluster_services + def chunks(l, n): """Yield successive n-sized chunks from l.""" @@ -215,7 +252,7 @@ def main(): argument_spec = dict( details=dict(type="bool", default=False), events=dict(type="bool", default=True), - cluster=dict(), + cluster=dict(type="list", elements="str"), service=dict(type="list", elements="str", aliases=["name"]), ) @@ -224,18 +261,20 @@ def main(): show_details = module.params.get("details") task_mgr = EcsServiceManager(module) + cluster_services = task_mgr.get_cluster_services() + if show_details: - if module.params["service"]: - services = module.params["service"] - else: - services = task_mgr.list_services(module.params["cluster"])["services"] ecs_info = dict(services=[], services_not_running=[]) - for chunk in chunks(services, 10): - running_services, services_not_running = task_mgr.describe_services(module.params["cluster"], chunk) - ecs_info["services"].extend(running_services) - ecs_info["services_not_running"].extend(services_not_running) + for cluster, services in cluster_services.items(): + for chunk in chunks(services, 10): + running_services, services_not_running = task_mgr.describe_services(cluster, chunk) + ecs_info["services"].extend(running_services) + ecs_info["services_not_running"].extend(services_not_running) else: - ecs_info = task_mgr.list_services(module.params["cluster"]) + service_arns = [] + for service_list in cluster_services.values(): + service_arns.extend(service_list) + ecs_info = dict(services=service_arns) module.exit_json(changed=False, **ecs_info) diff --git a/tests/integration/targets/ecs_cluster/tasks/10_ecs_cluster.yml b/tests/integration/targets/ecs_cluster/tasks/10_ecs_cluster.yml index f2c868674f8..b593b337b9f 100644 --- a/tests/integration/targets/ecs_cluster/tasks/10_ecs_cluster.yml +++ b/tests/integration/targets/ecs_cluster/tasks/10_ecs_cluster.yml @@ -1,4 +1,16 @@ # cluster "{{ ecs_cluster_name }}" is used for ecs_service tests +- name: get existing service info + ecs_service_info: + details: true + events: false + register: ecs_service_info + +- name: check that no services exist and the module does not error + assert: + that: + - ecs_service_info.services is defined + - ecs_service_info.services | length == 0 + - name: create an ECS cluster ecs_cluster: name: "{{ ecs_cluster_name }}" diff --git a/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml b/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml index 3c4bbcb28c7..59c454762e0 100644 --- a/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml +++ b/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml @@ -400,8 +400,7 @@ - name: obtain facts for existing service in the cluster ecs_service_info: - cluster: "{{ ecs_cluster_name }}" - service: "{{ ecs_service_name }}" + service: "{{ ecs_service_name }}2" details: true events: false register: ecs_service_info @@ -423,7 +422,7 @@ - name: assert that non-existent service is missing assert: that: - - "ecs_service_info.services_not_running[0].reason == 'MISSING'" + - "ecs_service_info.services|length == 0" - name: obtain specific ECS service facts ecs_service_info: @@ -437,6 +436,19 @@ that: - "'networkConfiguration' in ecs_service_info.services[0]" +- name: obtain facts for all clusters + ecs_service_info: + details: true + events: false + register: ecs_service_info + +- name: assert that service info is available + assert: + that: + - "ecs_service_info.services|length == 3" + - "ecs_service_info.services_not_running|length == 0" + - "ecs_cluster_name in ecs_service_info.services[0].clusterArn" + - name: attempt to get facts from missing task definition ecs_taskdefinition_info: task_definition: "{{ ecs_task_name }}-vpc:{{ ecs_task_definition.taskdefinition.revision + 1}}" @@ -547,7 +559,7 @@ >> "rolloutStateReason": "ECS deployment ecs-svc/5156684577543126023 in progress.", constraints and placement strategies are only changeable if the rollout state is "COMPLETED" - + a) ecs_service has currently no waiter function. so this is a DIY waiter b) the state reached never "COMPLETED" because something if wrong with the ECS EC2 Instances or the network setup. The EC2 instance never arrived as an active instance in the cluster. @@ -555,9 +567,9 @@ >> no container instance met all of its requirements. Reason: No Container Instances were found in your cluster. >> For more information, see the Troubleshooting section of the Amazon ECS Developer Guide. >> ec2_instance networking does not work correctly, no instance available for the cluster - + Because all of this, all following tasks, that test the change of a constraint or placement stragegy are - using `force_new_deployment: true`. That ignores a) and b). + using `force_new_deployment: true`. That ignores a) and b). ignore_errors: true ecs_service_info: name: "{{ ecs_service_name }}-constraint"