Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECS service - add tag+propagate_tags upon creation. #543

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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:
tamirhad marked this conversation as resolved.
Show resolved Hide resolved
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:
tamirhad marked this conversation as resolved.
Show resolved Hide resolved
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")
tremble marked this conversation as resolved.
Show resolved Hide resolved

# 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
tamirhad marked this conversation as resolved.
Show resolved Hide resolved

- 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