From d8333fdd7ea2e505d5a434bdea8a0f1b785bfb52 Mon Sep 17 00:00:00 2001 From: Jim Shields Date: Thu, 3 Oct 2019 14:30:08 -0400 Subject: [PATCH] Add support for tagging of ECS services * Add tags to create_service * Add service to list_tags_for_resource --- moto/ecs/models.py | 15 +++++++--- moto/ecs/responses.py | 3 +- tests/test_ecs/test_ecs_boto3.py | 51 ++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/moto/ecs/models.py b/moto/ecs/models.py index 863cfc49e..37ff49fe8 100644 --- a/moto/ecs/models.py +++ b/moto/ecs/models.py @@ -192,7 +192,7 @@ class Task(BaseObject): class Service(BaseObject): - def __init__(self, cluster, service_name, task_definition, desired_count, load_balancers=None, scheduling_strategy=None): + def __init__(self, cluster, service_name, task_definition, desired_count, load_balancers=None, scheduling_strategy=None, tags=None): self.cluster_arn = cluster.arn self.arn = 'arn:aws:ecs:us-east-1:012345678910:service/{0}'.format( service_name) @@ -216,6 +216,7 @@ class Service(BaseObject): ] self.load_balancers = load_balancers if load_balancers is not None else [] self.scheduling_strategy = scheduling_strategy if scheduling_strategy is not None else 'REPLICA' + self.tags = tags if tags is not None else [] self.pending_count = 0 @property @@ -225,7 +226,7 @@ class Service(BaseObject): @property def response_object(self): response_object = self.gen_response_object() - del response_object['name'], response_object['arn'] + del response_object['name'], response_object['arn'], response_object['tags'] response_object['serviceName'] = self.name response_object['serviceArn'] = self.arn response_object['schedulingStrategy'] = self.scheduling_strategy @@ -691,7 +692,7 @@ class EC2ContainerServiceBackend(BaseBackend): raise Exception("Could not find task {} on cluster {}".format( task_str, cluster_name)) - def create_service(self, cluster_str, service_name, task_definition_str, desired_count, load_balancers=None, scheduling_strategy=None): + def create_service(self, cluster_str, service_name, task_definition_str, desired_count, load_balancers=None, scheduling_strategy=None, tags=None): cluster_name = cluster_str.split('/')[-1] if cluster_name in self.clusters: cluster = self.clusters[cluster_name] @@ -701,7 +702,7 @@ class EC2ContainerServiceBackend(BaseBackend): desired_count = desired_count if desired_count is not None else 0 service = Service(cluster, service_name, - task_definition, desired_count, load_balancers, scheduling_strategy) + task_definition, desired_count, load_balancers, scheduling_strategy, tags) cluster_service_pair = '{0}:{1}'.format(cluster_name, service_name) self.services[cluster_service_pair] = service @@ -974,6 +975,12 @@ class EC2ContainerServiceBackend(BaseBackend): return revision.tags else: raise TaskDefinitionNotFoundException() + elif service == "service": + for _service in self.services.values(): + if _service.arn == resource_arn: + return _service.tags + else: + raise ServiceNotFoundException(service_name=match.group("id")) raise NotImplementedError() def _get_last_task_definition_revision_id(self, family): diff --git a/moto/ecs/responses.py b/moto/ecs/responses.py index abb79ea78..fb162de3b 100644 --- a/moto/ecs/responses.py +++ b/moto/ecs/responses.py @@ -156,8 +156,9 @@ class EC2ContainerServiceResponse(BaseResponse): desired_count = self._get_int_param('desiredCount') load_balancers = self._get_param('loadBalancers') scheduling_strategy = self._get_param('schedulingStrategy') + tags = self._get_param('tags') service = self.ecs_backend.create_service( - cluster_str, service_name, task_definition_str, desired_count, load_balancers, scheduling_strategy) + cluster_str, service_name, task_definition_str, desired_count, load_balancers, scheduling_strategy, tags) return json.dumps({ 'service': service.response_object }) diff --git a/tests/test_ecs/test_ecs_boto3.py b/tests/test_ecs/test_ecs_boto3.py index 9937af26b..d6fb0ff2e 100644 --- a/tests/test_ecs/test_ecs_boto3.py +++ b/tests/test_ecs/test_ecs_boto3.py @@ -2360,3 +2360,54 @@ def test_list_tags_for_resource_unknown(): client.list_tags_for_resource(resourceArn=task_definition_arn) except ClientError as err: err.response['Error']['Code'].should.equal('ClientException') + + +@mock_ecs +def test_list_tags_for_resource_ecs_service(): + client = boto3.client('ecs', region_name='us-east-1') + _ = client.create_cluster( + clusterName='test_ecs_cluster' + ) + _ = client.register_task_definition( + family='test_ecs_task', + containerDefinitions=[ + { + 'name': 'hello_world', + 'image': 'docker/hello-world:latest', + 'cpu': 1024, + 'memory': 400, + 'essential': True, + 'environment': [{ + 'name': 'AWS_ACCESS_KEY_ID', + 'value': 'SOME_ACCESS_KEY' + }], + 'logConfiguration': {'logDriver': 'json-file'} + } + ] + ) + response = client.create_service( + cluster='test_ecs_cluster', + serviceName='test_ecs_service', + taskDefinition='test_ecs_task', + desiredCount=2, + tags=[ + {'key': 'createdBy', 'value': 'moto-unittest'}, + {'key': 'foo', 'value': 'bar'}, + ] + ) + response = client.list_tags_for_resource(resourceArn=response['service']['serviceArn']) + type(response['tags']).should.be(list) + response['tags'].should.equal([ + {'key': 'createdBy', 'value': 'moto-unittest'}, + {'key': 'foo', 'value': 'bar'}, + ]) + + +@mock_ecs +def test_list_tags_for_resource_unknown_service(): + client = boto3.client('ecs', region_name='us-east-1') + service_arn = 'arn:aws:ecs:us-east-1:012345678910:service/unknown:1' + try: + client.list_tags_for_resource(resourceArn=service_arn) + except ClientError as err: + err.response['Error']['Code'].should.equal('ServiceNotFoundException')