Skip to content

Commit

Permalink
ECS service - add tag+propagate_tags upon creation. (#543) (#1317)
Browse files Browse the repository at this point in the history
[PR #543/e3c8302c backport][stable-4] ECS service - add tag+propagate_tags upon creation.

This is a backport of PR #543 as merged into main (e3c8302).
SUMMARY

this PR is continuation of #242
this PR will enable the use of tags at creation time, in addition to propagate_tags.

ISSUE TYPE


Feature Pull Request

COMPONENT NAME

ecs_service
ADDITIONAL INFORMATION


this PR is continuation of #242
i cant contribute to his repo as i am not a maintainer so i created a new PR, if its not the right git flow please be gentle, its my first time :)

Reviewed-by: Mark Chappell <None>
  • Loading branch information
patchback[bot] authored Jul 6, 2022
1 parent 6f21cb9 commit bbbdaf2
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 41 deletions.
3 changes: 3 additions & 0 deletions changelogs/fragments/543-ecs_propagate_tags_support.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- ecs_service - added ``tags`` and ``tag_propagation`` support to the module (https://github.com/ansible-collections/community.aws/pull/543).
102 changes: 91 additions & 11 deletions plugins/modules/ecs_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type


DOCUMENTATION = r'''
---
module: ecs_service
Expand Down Expand Up @@ -252,14 +251,26 @@
type: bool
default: false
version_added: 4.1.0
propagate_tags:
description:
- Propagate tags from ECS task defintition or ECS service to ECS task.
required: false
choices: ["TASK_DEFINITION", "SERVICE"]
type: str
version_added: 4.1.0
tags:
description:
- A dictionary of tags to add or remove from the resource.
type: dict
required: false
version_added: 4.1.0
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
'''

EXAMPLES = r'''
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Basic provisioning example
- community.aws.ecs_service:
state: present
Expand Down Expand Up @@ -328,6 +339,18 @@
- capacity_provider: test-capacity-provider-1
weight: 1
base: 0
# With tags and tag propagation
- community.aws.ecs_service:
state: present
name: tags-test-service
cluster: new_cluster
task_definition: 'new_cluster-task:1'
desired_count: 1
tags:
Firstname: jane
lastName: doe
propagate_tags: SERVICE
'''

RETURN = r'''
Expand Down Expand Up @@ -401,6 +424,10 @@
description: The valid values are ACTIVE, DRAINING, or INACTIVE.
returned: always
type: str
tags:
description: The tags applied to this resource.
returned: success
type: dict
taskDefinition:
description: The ARN of a task definition to use for tasks in the service.
returned: always
Expand Down Expand Up @@ -472,7 +499,10 @@
such as attribute:ecs.availability-zone. For the binpack placement strategy, valid values are CPU and MEMORY.
returned: always
type: str
propagateTags:
description: The type of tag propagation applied to the resource.
returned: always
type: str
ansible_facts:
description: Facts about deleted service.
returned: when deleting a service
Expand Down Expand Up @@ -530,6 +560,11 @@
description: The valid values are ACTIVE, DRAINING, or INACTIVE.
returned: always
type: str
tags:
description: The tags applied to this resource.
returned: when tags found
type: list
elements: dict
taskDefinition:
description: The ARN of a task definition to use for tasks in the service.
returned: always
Expand Down Expand Up @@ -601,6 +636,11 @@
such as attribute:ecs.availability-zone. For the binpack placement strategy, valid values are CPU and MEMORY.
returned: always
type: str
propagateTags:
description: The type of tag propagation applied to the resource
returned: always
type: str
'''
import time

Expand All @@ -614,8 +654,13 @@
'deployment_circuit_breaker': 'dict',
}

from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict

from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict, map_complex_type, get_ec2_security_group_ids_from_names
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import map_complex_type
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_ec2_security_group_ids_from_names
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict

try:
import botocore
Expand Down Expand Up @@ -662,8 +707,11 @@ def find_in_array(self, array_of_services, service_name, field_name='serviceArn'
def describe_service(self, cluster_name, service_name):
response = self.ecs.describe_services(
cluster=cluster_name,
services=[service_name])
services=[service_name],
include=['TAGS'],
)
msg = ''

if len(response['failures']) > 0:
c = self.find_in_array(response['failures'], service_name, 'arn')
msg += ", failure reason is " + c['reason']
Expand Down Expand Up @@ -692,6 +740,12 @@ def is_matching_service(self, expected, existing):
if (expected['load_balancers'] or []) != existing['loadBalancers']:
return False

if expected['propagate_tags'] != existing['propagateTags']:
return False

if boto3_tag_list_to_ansible_dict(existing['tags']) != expected['tags']:
return False

# expected is params. DAEMON scheduling strategy returns desired count equal to
# number of instances running; don't check desired count if scheduling strat is daemon
if (expected['scheduling_strategy'] != 'DAEMON'):
Expand All @@ -704,7 +758,7 @@ def create_service(self, service_name, cluster_name, task_definition, load_balan
desired_count, client_token, role, deployment_controller, deployment_configuration,
placement_constraints, placement_strategy, health_check_grace_period_seconds,
network_configuration, service_registries, launch_type, platform_version,
scheduling_strategy, capacity_provider_strategy):
scheduling_strategy, capacity_provider_strategy, tags, propagate_tags):

params = dict(
cluster=cluster_name,
Expand Down Expand Up @@ -740,6 +794,14 @@ def create_service(self, service_name, cluster_name, task_definition, load_balan
params['desiredCount'] = desired_count
if capacity_provider_strategy:
params['capacityProviderStrategy'] = capacity_provider_strategy
if propagate_tags:
params['propagateTags'] = propagate_tags
# desired count is not required if scheduling strategy is daemon
if desired_count is not None:
params['desiredCount'] = desired_count
if tags:
params['tags'] = ansible_dict_to_boto3_tag_list(tags, 'key', 'value')

if scheduling_strategy:
params['schedulingStrategy'] = scheduling_strategy
response = self.ecs.create_service(**params)
Expand Down Expand Up @@ -850,7 +912,9 @@ def main():
weight=dict(type='int'),
base=dict(type='int')
)
)
),
propagate_tags=dict(required=False, choices=['TASK_DEFINITION', 'SERVICE']),
tags=dict(required=False, type='dict'),
)

module = AnsibleAWSModule(argument_spec=argument_spec,
Expand Down Expand Up @@ -888,7 +952,9 @@ def main():
try:
existing = service_mgr.describe_service(module.params['cluster'], module.params['name'])
except Exception as e:
module.fail_json(msg="Exception describing service '" + module.params['name'] + "' in cluster '" + module.params['cluster'] + "': " + str(e))
module.fail_json_aws(e,
msg="Exception describing service '{0}' in cluster '{1}'"
.format(module.params['name'], module.params['cluster']))

results = dict(changed=False)

Expand Down Expand Up @@ -948,6 +1014,12 @@ def main():
else:
task_definition = module.params['task_definition']

if module.params['propagate_tags'] and module.params['propagate_tags'] != existing['propagateTags']:
module.fail_json(msg="It is not currently supported to enable propagation tags of an existing service")

if module.params['tags'] and boto3_tag_list_to_ansible_dict(existing['tags']) != module.params['tags']:
module.fail_json(msg="It is not currently supported to change tags of an existing service")

# update required
response = service_mgr.update_service(module.params['name'],
module.params['cluster'],
Expand All @@ -957,7 +1029,7 @@ def main():
network_configuration,
module.params['health_check_grace_period_seconds'],
module.params['force_new_deployment'],
capacityProviders
capacityProviders,
)

else:
Expand All @@ -977,13 +1049,18 @@ def main():
network_configuration,
serviceRegistries,
module.params['launch_type'],
module.params['scheduling_strategy'],
module.params['platform_version'],
module.params['scheduling_strategy'],
capacityProviders
capacityProviders,
module.params['tags'],
module.params['propagate_tags'],
)
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e, msg="Couldn't create service")

if response.get('tags', None):
response['tags'] = boto3_tag_list_to_ansible_dict(response['tags'])
results['service'] = response

results['changed'] = True
Expand Down Expand Up @@ -1044,7 +1121,10 @@ def main():
break
time.sleep(delay)
if i is repeat - 1:
module.fail_json(msg="Service still not deleted after " + str(repeat) + " tries of " + str(delay) + " seconds each.")
module.fail_json(
msg="Service still not deleted after {0} tries of {1} seconds each."
.format(repeat, delay)
)
return

module.exit_json(**results)
Expand Down
93 changes: 63 additions & 30 deletions tests/integration/targets/ecs_tag/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,6 @@
that:
- taglist.changed == false

- name: cluster tags - List tags
ecs_tag:
cluster_name: "{{ resource_prefix}}"
resource: "{{ resource_prefix}}"
resource_type: cluster
state: list
register: taglist

- name: cluster tags - should have 2 tags
assert:
that:
- taglist.tags|list|length == 2
- taglist.failed == false
- taglist.changed == false

- name: cluster tags - remove tag another
ecs_tag:
cluster_name: "{{resource_prefix}}"
Expand Down Expand Up @@ -249,21 +234,6 @@
- taglist.changed == false
- taglist.tags.Name == "task_definition-{{ resource_prefix }}"

- name: task_definition tags - retrieve all tags on a task_definition
ecs_tag:
cluster_name: "{{resource_prefix}}"
resource: "{{ecs_taskdefinition_creation.taskdefinition.family}}"
resource_type: task_definition
state: list
register: taglist

- name: task_definition tags - should have 1 tag
assert:
that:
- taglist.tags|list|length == 1
- taglist.failed == false
- taglist.changed == false

- name: task_definition tags - remove task_definition tags
ecs_tag:
cluster_name: "{{resource_prefix}}"
Expand All @@ -281,6 +251,51 @@
- taglist.changed == true
- '"Name" not in taglist.tags'

# Test tags and tags_propagate with service creation

- name: create ecs_service with tags
ecs_service:
name: "{{ resource_prefix }}-tags"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
state: present
tags:
Name: foo
"Last Name": bar
register: ecs_service_creation_tags

- name: ecs_service up
assert:
that:
- ecs_service_creation_tags.changed

- name: service tags - tags should be there
assert:
that:
- '"Name" in ecs_service_creation_tags.service.tags'
- '"Last Name" in ecs_service_creation_tags.service.tags'
- ecs_service_creation_tags.service.tags.Name == "foo"
- ecs_service_creation_tags.service.tags["Last Name"] == "bar"

- name: create the same ecs_service with tags
ecs_service:
name: "{{ resource_prefix }}-tags"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
state: present
tags:
test: test
ignore_errors: yes
register: ecs_service_creation_again

- name: check that creation again with tags failed
assert:
that:
- ecs_service_creation_again is failed
- '"msg" in ecs_service_creation_again'

always:
- name: scale down ecs service
ecs_service:
Expand All @@ -291,6 +306,15 @@
state: present
ignore_errors: yes

- name: scale down ecs service
ecs_service:
name: "{{ resource_prefix }}-tags"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 0
state: present
ignore_errors: yes

- name: pause to wait for scale down
pause:
seconds: 30
Expand All @@ -304,6 +328,15 @@
state: absent
ignore_errors: yes

- name: remove ecs service
ecs_service:
name: "{{ resource_prefix }}-tags"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
state: absent
ignore_errors: yes

- name: remove ecs task definition
ecs_taskdefinition:
containers:
Expand Down

0 comments on commit bbbdaf2

Please sign in to comment.