diff --git a/lib/ansible/modules/cloud/amazon/ecs_taskdefinition.py b/lib/ansible/modules/cloud/amazon/ecs_taskdefinition.py index ac336fce81..37aacf681a 100644 --- a/lib/ansible/modules/cloud/amazon/ecs_taskdefinition.py +++ b/lib/ansible/modules/cloud/amazon/ecs_taskdefinition.py @@ -69,6 +69,11 @@ options: the permissions that are specified in this role. required: false version_added: 2.3 + execution_role_arn: + description: + - The Amazon Resource Name (ARN) of the task execution role that the Amazon ECS container agent and the Docker daemon can assume. + required: false + version_added: 2.7 volumes: description: - A list of names of volumes to be attached @@ -180,7 +185,7 @@ try: except ImportError: HAS_BOTO3 = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.aws.core import AnsibleAWSModule from ansible.module_utils.ec2 import boto3_conn, camel_dict_to_snake_dict, ec2_argument_spec, get_aws_connection_info from ansible.module_utils._text import to_text @@ -201,7 +206,7 @@ class EcsTaskManager: except botocore.exceptions.ClientError: return None - def register_task(self, family, task_role_arn, network_mode, container_definitions, volumes, launch_type, cpu, memory): + def register_task(self, family, task_role_arn, execution_role_arn, network_mode, container_definitions, volumes, launch_type, cpu, memory): validated_containers = [] # Ensures the number parameters are int as required by boto @@ -235,6 +240,8 @@ class EcsTaskManager: params['memory'] = memory if launch_type: params['requiresCompatibilities'] = [launch_type] + if execution_role_arn: + params['executionRoleArn'] = execution_role_arn try: response = self.ecs.register_task_definition(**params) @@ -279,12 +286,6 @@ class EcsTaskManager: response = self.ecs.deregister_task_definition(taskDefinition=taskArn) return response['taskDefinition'] - def ecs_api_supports_requirescompatibilities(self): - from distutils.version import LooseVersion - # Checking to make sure botocore is greater than a specific version. - # Support for requiresCompatibilities is only available in versions beyond 1.8.4 - return LooseVersion(botocore.__version__) >= LooseVersion('1.8.4') - def main(): argument_spec = ec2_argument_spec() @@ -297,16 +298,17 @@ def main(): containers=dict(required=False, type='list'), network_mode=dict(required=False, default='bridge', choices=['bridge', 'host', 'none', 'awsvpc'], type='str'), task_role_arn=dict(required=False, default='', type='str'), + execution_role_arn=dict(required=False, default='', type='str'), volumes=dict(required=False, type='list'), launch_type=dict(required=False, choices=['EC2', 'FARGATE']), cpu=dict(), memory=dict(required=False, type='str') )) - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True, - required_if=[('launch_type', 'FARGATE', ['cpu', 'memory'])] - ) + module = AnsibleAWSModule(argument_spec=argument_spec, + supports_check_mode=True, + required_if=[('launch_type', 'FARGATE', ['cpu', 'memory'])] + ) if not HAS_BOTO3: module.fail_json(msg='boto3 is required.') @@ -316,9 +318,13 @@ def main(): results = dict(changed=False) if module.params['launch_type']: - if not task_mgr.ecs_api_supports_requirescompatibilities(): + if not module.botocore_at_least('1.8.4'): module.fail_json(msg='botocore needs to be version 1.8.4 or higher to use launch_type') + if module.params['execution_role_arn']: + if not module.botocore_at_least('1.10.44'): + module.fail_json(msg='botocore needs to be version 1.10.44 or higher to use execution_role_arn') + for container in module.params.get('containers', []): for environment in container.get('environment', []): environment['value'] = to_text(environment['value']) @@ -442,6 +448,7 @@ def main(): volumes = module.params.get('volumes', []) or [] results['taskdefinition'] = task_mgr.register_task(module.params['family'], module.params['task_role_arn'], + module.params['execution_role_arn'], module.params['network_mode'], module.params['containers'], volumes, diff --git a/test/integration/targets/ecs_cluster/playbooks/network_fail.yml b/test/integration/targets/ecs_cluster/playbooks/network_fail.yml index 72c2f8876e..7d026d806f 100644 --- a/test/integration/targets/ecs_cluster/playbooks/network_fail.yml +++ b/test/integration/targets/ecs_cluster/playbooks/network_fail.yml @@ -44,6 +44,26 @@ <<: *aws_connection_info register: ecs_taskdefinition_creation_vpc + - name: create ecs_taskdefinition and execution_role_arn (expected to fail) + ecs_taskdefinition: + containers: + - name: my_container + image: ubuntu + memory: 128 + family: "{{ resource_prefix }}-vpc" + execution_role_arn: not_a_real_arn + state: present + network_mode: awsvpc + <<: *aws_connection_info + ignore_errors: yes + register: ecs_taskdefinition_arn + + - name: check that graceful failure message is returned from ecs_taskdefinition_arn + assert: + that: + - ecs_taskdefinition_arn.failed + - 'ecs_taskdefinition_arn.msg == "botocore needs to be version 1.10.44 or higher to use execution_role_arn"' + - name: ecs_taskdefinition works fine even when older botocore is used assert: that: diff --git a/test/integration/targets/ecs_cluster/playbooks/roles/ecs_cluster/tasks/main.yml b/test/integration/targets/ecs_cluster/playbooks/roles/ecs_cluster/tasks/main.yml index c30cdb2a99..9a19e1503c 100644 --- a/test/integration/targets/ecs_cluster/playbooks/roles/ecs_cluster/tasks/main.yml +++ b/test/integration/targets/ecs_cluster/playbooks/roles/ecs_cluster/tasks/main.yml @@ -541,6 +541,18 @@ # ============================================================ # Begin tests for Fargate + - name: ensure AmazonECSTaskExecutionRolePolicy exists + iam_role: + name: ecsTaskExecutionRole + assume_role_policy_document: "{{ lookup('file','ecs-trust-policy.json') }}" + description: "Allows ECS containers to make calls to ECR" + state: present + create_instance_profile: no + managed_policy: + - AmazonEC2ContainerServiceRole + <<: *aws_connection_info + register: iam_execution_role + - name: create Fargate VPC-networked task definition with host port set to 8080 and unsupported network mode (expected to fail) ecs_taskdefinition: containers: "{{ ecs_fargate_task_containers }}" @@ -579,7 +591,7 @@ - ecs_fargate_task_definition_vpc_no_mem is failed - 'ecs_fargate_task_definition_vpc_no_mem.msg == "launch_type is FARGATE but all of the following are missing: cpu, memory"' - - name: create Fargate VPC-networked task definition with CPU or Memory + - name: create Fargate VPC-networked task definition with CPU or Memory and execution role ecs_taskdefinition: containers: "{{ ecs_fargate_task_containers }}" family: "{{ ecs_task_name }}-vpc" @@ -587,6 +599,7 @@ launch_type: FARGATE cpu: 512 memory: 1024 + execution_role_arn: "{{ iam_execution_role.arn }}" state: present <<: *aws_connection_info vars: