From 4b52107384aba65f80ad61784f42a6ba91c77320 Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Sun, 9 May 2021 21:11:47 +0200 Subject: [PATCH 1/4] ecs_taskdefinition: Fix some parameters cast to int Signed-off-by: Alina Buzachis --- plugins/modules/ecs_taskdefinition.py | 38 ++- .../targets/ecs_cluster/defaults/main.yml | 5 + .../targets/ecs_cluster/tasks/full_test.yml | 220 +++++++++--------- 3 files changed, 145 insertions(+), 118 deletions(-) diff --git a/plugins/modules/ecs_taskdefinition.py b/plugins/modules/ecs_taskdefinition.py index 6696e92acb3..dbd3a9638ee 100644 --- a/plugins/modules/ecs_taskdefinition.py +++ b/plugins/modules/ecs_taskdefinition.py @@ -189,7 +189,7 @@ linuxParameters: description: Linux-specific modifications that are applied to the container, such as Linux kernel capabilities. required: False - type: list + type: dict suboptions: capabilities: description: @@ -410,6 +410,8 @@ description: The type of the ulimit. type: str required: False + choices: ['core', 'cpu', 'data', 'fsize', 'locks', 'memlock', 'msgqueue', 'nice', 'nofile', 'nproc', 'rss', + 'rtprio', 'rttime', 'sigpending', 'stack'] softLimit: description: The soft limit for the ulimit type. type: int @@ -667,7 +669,7 @@ def register_task(self, family, task_role_arn, execution_role_arn, network_mode, # Ensures the number parameters are int as required by boto for container in container_definitions: - for param in ('memory', 'cpu', 'memoryReservation'): + for param in ('memory', 'cpu', 'memoryReservation', 'startTimeout', 'stopTimeout'): if param in container: container[param] = int(container[param]) @@ -681,6 +683,23 @@ def register_task(self, family, task_role_arn, execution_role_arn, network_mode, self.module.fail_json(msg="In awsvpc network mode, host port must be set to the same as " "container port or not be set") + if 'linuxParameters' in container: + for linux_param in container.get('linuxParameters'): + if linux_param == 'tmpfs': + for tmpfs_param in container['linuxParameters']['tmpfs']: + if 'size' in tmpfs_param: + tmpfs_param['size'] = int(tmpfs_param['size']) + + for param in ('maxSwap', 'swappiness', 'sharedMemorySize'): + if param in linux_param: + container['linuxParameters'][param] = int(container['linuxParameters'][param]) + + if 'ulimits' in container: + for limits_mapping in container['ulimits']: + for limit in ('softLimit', 'hardLimit'): + if limit in limits_mapping: + limits_mapping[limit] = int(limits_mapping[limit]) + validated_containers.append(container) params = dict( @@ -802,21 +821,24 @@ def main(): module.fail_json(msg='The only supported value for environmentFiles is s3.') for linux_param in container.get('linuxParameters', {}): - if linux_param.get('devices') and launch_type == 'FARGATE': + if linux_param == 'maxSwap' and launch_type == 'FARGATE': module.fail_json(msg='devices parameter is not supported with the FARGATE launch type.') - if linux_param.get('maxSwap') and launch_type == 'FARGATE': + if linux_param == 'maxSwap' and launch_type == 'FARGATE': module.fail_json(msg='maxSwap parameter is not supported with the FARGATE launch type.') - elif linux_param.get('maxSwap') and linux_param['maxSwap'] < 0: + elif linux_param == 'maxSwap' and container['linuxParameters']['maxSwap'] < 0: module.fail_json(msg='Accepted values for maxSwap are 0 or any positive integer.') - if linux_param.get('swappiness') and (linux_param['swappiness'] < 0 or linux_param['swappiness'] > 100): + if ( + linux_param == 'swappiness' and + (container['linuxParameters']['swappiness'] < 0 or container['linuxParameters']['swappiness'] > 100) + ): module.fail_json(msg='Accepted values for swappiness are whole numbers between 0 and 100.') - if linux_param.get('sharedMemorySize') and launch_type == 'FARGATE': + if linux_param == 'sharedMemorySize' and launch_type == 'FARGATE': module.fail_json(msg='sharedMemorySize parameter is not supported with the FARGATE launch type.') - if linux_param.get('tmpfs') and launch_type == 'FARGATE': + if linux_param == 'tmpfs' and launch_type == 'FARGATE': module.fail_json(msg='tmpfs parameter is not supported with the FARGATE launch type.') if container.get('hostname') and network_mode == 'awsvpc': diff --git a/tests/integration/targets/ecs_cluster/defaults/main.yml b/tests/integration/targets/ecs_cluster/defaults/main.yml index 20e010e366d..0a34cf0232e 100644 --- a/tests/integration/targets/ecs_cluster/defaults/main.yml +++ b/tests/integration/targets/ecs_cluster/defaults/main.yml @@ -7,6 +7,8 @@ ecs_service_name: "{{ resource_prefix }}-service" ecs_task_image_path: nginx ecs_task_name: "{{ resource_prefix }}-task" ecs_task_memory: 128 +target_swap_mb: 0 +target_swappiness: 80 ecs_task_containers: - name: "{{ ecs_task_name }}" image: "{{ ecs_task_image_path }}" @@ -15,6 +17,9 @@ ecs_task_containers: portMappings: - containerPort: "{{ ecs_task_container_port }}" hostPort: "{{ ecs_task_host_port|default(0) }}" + linuxParameters: + maxSwap: "{{ target_swap_mb }}" + swappiness: "{{ target_swappiness }}" mountPoints: "{{ ecs_task_mount_points|default([]) }}" ecs_service_deployment_configuration: minimum_healthy_percent: 0 diff --git a/tests/integration/targets/ecs_cluster/tasks/full_test.yml b/tests/integration/targets/ecs_cluster/tasks/full_test.yml index a463fa5de0d..10dc04eaf50 100644 --- a/tests/integration/targets/ecs_cluster/tasks/full_test.yml +++ b/tests/integration/targets/ecs_cluster/tasks/full_test.yml @@ -72,7 +72,7 @@ - name: create subnets ec2_vpc_subnet: - az: '{{ ec2_region }}{{ item.zone }}' + az: '{{ aws_region }}{{ item.zone }}' tags: Name: '{{ resource_prefix }}_ecs_cluster-subnet-{{ item.zone }}' vpc_id: '{{ setup_vpc.vpc.id }}' @@ -150,24 +150,24 @@ target_type: ip register: elb_target_group_ip - - name: create load balancer - elb_application_lb: - name: "{{ ecs_load_balancer_name }}" - state: present - scheme: internal - security_groups: '{{ setup_sg.group_id }}' - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" - listeners: - - Protocol: HTTP - Port: 80 - DefaultActions: - - Type: forward - TargetGroupName: "{{ ecs_target_group_name }}1" - - Protocol: HTTP - Port: 81 - DefaultActions: - - Type: forward - TargetGroupName: "{{ ecs_target_group_name }}2" + # - name: create load balancer + # elb_application_lb: + # name: "{{ ecs_load_balancer_name }}" + # state: present + # scheme: internal + # security_groups: '{{ setup_sg.group_id }}' + # subnets: "{{ setup_subnet.results | map(attribute="subnet.id") }}" + # listeners: + # - Protocol: HTTP + # Port: 80 + # DefaultActions: + # - Type: forward + # TargetGroupName: "{{ ecs_target_group_name }}1" + # - Protocol: HTTP + # Port: 81 + # DefaultActions: + # - Type: forward + # TargetGroupName: "{{ ecs_target_group_name }}2" - name: create task definition ecs_taskdefinition: @@ -240,94 +240,94 @@ # FIXME: service should not change, needs fixing ignore_errors: yes - # FIXME: attempt to update service load balancer - - name: update ECS service definition (expected to fail) - ecs_service: - state: present - name: "{{ ecs_service_name }}" - cluster: "{{ ecs_cluster_name }}" - task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" - desired_count: 1 - deployment_configuration: "{{ ecs_service_deployment_configuration }}" - placement_strategy: "{{ ecs_service_placement_strategy }}" - health_check_grace_period_seconds: "{{ ecs_service_health_check_grace_period }}" - load_balancers: - - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" - containerName: "{{ ecs_task_name }}" - containerPort: "{{ ecs_task_container_port|int + 1 }}" - role: "ecsServiceRole" - register: update_ecs_service - ignore_errors: yes - - - name: assert that updating ECS load balancer failed with helpful message - assert: - that: - - update_ecs_service is failed - - "'error' not in update_ecs_service" - - "'msg' in update_ecs_service" - - - - name: attempt to use ECS network configuration on task definition without awsvpc network_mode - ecs_service: - state: present - name: "{{ ecs_service_name }}3" - cluster: "{{ ecs_cluster_name }}" - task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" - desired_count: 1 - deployment_configuration: "{{ ecs_service_deployment_configuration }}" - placement_strategy: "{{ ecs_service_placement_strategy }}" - load_balancers: - - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" - containerName: "{{ ecs_task_name }}" - containerPort: "{{ ecs_task_container_port }}" - network_configuration: - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" - security_groups: - - '{{ setup_sg.group_id }}' - register: ecs_service_network_without_awsvpc_task - ignore_errors: yes - - - name: assert that using ECS network configuration with non AWSVPC task definition fails - assert: - that: - - ecs_service_network_without_awsvpc_task is failed - - - name: scale down ECS service - ecs_service: - state: present - name: "{{ ecs_service_name }}" - cluster: "{{ ecs_cluster_name }}" - task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" - desired_count: 0 - deployment_configuration: "{{ ecs_service_deployment_configuration }}" - placement_strategy: "{{ ecs_service_placement_strategy }}" - load_balancers: - - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" - containerName: "{{ ecs_task_name }}" - containerPort: "{{ ecs_task_container_port }}" - role: "ecsServiceRole" - register: ecs_service_scale_down - - - name: pause to allow service to scale down - pause: - seconds: 60 - - - name: delete ECS service definition - ecs_service: - state: absent - name: "{{ ecs_service_name }}" - cluster: "{{ ecs_cluster_name }}" - register: delete_ecs_service - - - name: assert that deleting ECS service worked - assert: - that: - - delete_ecs_service.changed - - - name: assert that deleting ECS service worked - assert: - that: - - delete_ecs_service.changed + # # FIXME: attempt to update service load balancer + # - name: update ECS service definition (expected to fail) + # ecs_service: + # state: present + # name: "{{ ecs_service_name }}" + # cluster: "{{ ecs_cluster_name }}" + # task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" + # desired_count: 1 + # deployment_configuration: "{{ ecs_service_deployment_configuration }}" + # placement_strategy: "{{ ecs_service_placement_strategy }}" + # health_check_grace_period_seconds: "{{ ecs_service_health_check_grace_period }}" + # load_balancers: + # - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" + # containerName: "{{ ecs_task_name }}" + # containerPort: "{{ ecs_task_container_port|int + 1 }}" + # role: "ecsServiceRole" + # register: update_ecs_service + # ignore_errors: yes + + # - name: assert that updating ECS load balancer failed with helpful message + # assert: + # that: + # - update_ecs_service is failed + # - "'error' not in update_ecs_service" + # - "'msg' in update_ecs_service" + + + # - name: attempt to use ECS network configuration on task definition without awsvpc network_mode + # ecs_service: + # state: present + # name: "{{ ecs_service_name }}3" + # cluster: "{{ ecs_cluster_name }}" + # task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" + # desired_count: 1 + # deployment_configuration: "{{ ecs_service_deployment_configuration }}" + # placement_strategy: "{{ ecs_service_placement_strategy }}" + # load_balancers: + # - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" + # containerName: "{{ ecs_task_name }}" + # containerPort: "{{ ecs_task_container_port }}" + # network_configuration: + # subnets: "{{ setup_subnet.results | map(attribute='subnet.id') }}" + # security_groups: + # - '{{ setup_sg.group_id }}' + # register: ecs_service_network_without_awsvpc_task + # ignore_errors: yes + + # - name: assert that using ECS network configuration with non AWSVPC task definition fails + # assert: + # that: + # - ecs_service_network_without_awsvpc_task is failed + + # - name: scale down ECS service + # ecs_service: + # state: present + # name: "{{ ecs_service_name }}" + # cluster: "{{ ecs_cluster_name }}" + # task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" + # desired_count: 0 + # deployment_configuration: "{{ ecs_service_deployment_configuration }}" + # placement_strategy: "{{ ecs_service_placement_strategy }}" + # load_balancers: + # - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" + # containerName: "{{ ecs_task_name }}" + # containerPort: "{{ ecs_task_container_port }}" + # role: "ecsServiceRole" + # register: ecs_service_scale_down + + # - name: pause to allow service to scale down + # pause: + # seconds: 60 + + # - name: delete ECS service definition + # ecs_service: + # state: absent + # name: "{{ ecs_service_name }}" + # cluster: "{{ ecs_cluster_name }}" + # register: delete_ecs_service + + # - name: assert that deleting ECS service worked + # assert: + # that: + # - delete_ecs_service.changed + + # - name: assert that deleting ECS service worked + # assert: + # that: + # - delete_ecs_service.changed - name: create VPC-networked task definition with host port set to 0 (expected to fail) ecs_taskdefinition: @@ -389,7 +389,7 @@ containerName: "{{ ecs_task_name }}" containerPort: "{{ ecs_task_container_port }}" network_configuration: - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') }}" security_groups: - '{{ setup_sg.group_id }}' register: create_ecs_service_with_vpc @@ -423,7 +423,7 @@ containerName: "{{ ecs_task_name }}" containerPort: "{{ ecs_task_container_port }}" network_configuration: - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') }}" security_groups: - "{{ resource_prefix }}-ecs-vpc-test-sg" register: update_ecs_service_with_vpc @@ -674,7 +674,7 @@ deployment_configuration: "{{ ecs_service_deployment_configuration }}" launch_type: FARGATE network_configuration: - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id) }}" security_groups: - '{{ setup_sg.group_id }}' assign_public_ip: true From b0328c8c8960030aca5b8c4ace26f39790b9578d Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Mon, 10 May 2021 12:49:47 +0200 Subject: [PATCH 2/4] Fix idempotence Signed-off-by: Alina Buzachis --- plugins/modules/ecs_taskdefinition.py | 33 ++- .../targets/ecs_cluster/tasks/full_test.yml | 232 +++++++++--------- 2 files changed, 137 insertions(+), 128 deletions(-) diff --git a/plugins/modules/ecs_taskdefinition.py b/plugins/modules/ecs_taskdefinition.py index dbd3a9638ee..13a68ec0d66 100644 --- a/plugins/modules/ecs_taskdefinition.py +++ b/plugins/modules/ecs_taskdefinition.py @@ -13,7 +13,10 @@ short_description: register a task definition in ecs description: - Registers or deregisters task definitions in the Amazon Web Services (AWS) EC2 Container Service (ECS). -author: Mark Chance (@Java1Guy) +author: + - Mark Chance (@Java1Guy) + - Alina Buzachis (@alinabuzachis) +requirements: [ json, botocore, boto3 ] options: state: description: @@ -644,9 +647,9 @@ except ImportError: pass # caught by AnsibleAWSModule -from ansible.module_utils._text import to_text from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry class EcsTaskManager: @@ -655,13 +658,13 @@ class EcsTaskManager: def __init__(self, module): self.module = module - self.ecs = module.client('ecs') + self.ecs = module.client('ecs', AWSRetry.jittered_backoff()) def describe_task(self, task_name): try: - response = self.ecs.describe_task_definition(taskDefinition=task_name) + response = self.ecs.describe_task_definition(aws_retry=True, taskDefinition=task_name) return response['taskDefinition'] - except botocore.exceptions.ClientError: + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: return None def register_task(self, family, task_role_arn, execution_role_arn, network_mode, container_definitions, volumes, launch_type, cpu, memory): @@ -720,8 +723,8 @@ def register_task(self, family, task_role_arn, execution_role_arn, network_mode, params['executionRoleArn'] = execution_role_arn try: - response = self.ecs.register_task_definition(**params) - except botocore.exceptions.ClientError as e: + response = self.ecs.register_task_definition(aws_retry=True, **params) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: self.module.fail_json_aws(e, msg="Failed to register task") return response['taskDefinition'] @@ -814,7 +817,7 @@ def main(): module.fail_json(msg='links parameter is not supported if network mode is awsvpc.') for environment in container.get('environment', []): - environment['value'] = to_text(environment['value']) + environment['value'] = environment['value'] for environment_file in container.get('environmentFiles', []): if environment_file['type'] != 's3': @@ -884,14 +887,24 @@ def _right_has_values_of_left(left, right): for list_val in left_list: if list_val not in right_list: - return False + # if list_val is the port mapping, the key 'protocol' may be absent (but defaults to 'tcp') + # fill in that default if absent and see if it is in right_list then + if isinstance(list_val, dict) and not list_val.get('protocol'): + modified_list_val = dict(list_val) + modified_list_val.update(protocol='tcp') + if modified_list_val in right_list: + continue else: return False # Make sure right doesn't have anything that left doesn't for k, v in right.items(): if v and k not in left: - return False + # 'essential' defaults to True when not specified + if k == 'essential' and v is True: + pass + else: + return False return True diff --git a/tests/integration/targets/ecs_cluster/tasks/full_test.yml b/tests/integration/targets/ecs_cluster/tasks/full_test.yml index 10dc04eaf50..fbf50cf05db 100644 --- a/tests/integration/targets/ecs_cluster/tasks/full_test.yml +++ b/tests/integration/targets/ecs_cluster/tasks/full_test.yml @@ -116,7 +116,7 @@ - name: provision ec2 instance to create an image ec2_instance: key_name: '{{ ec2_keypair|default(setup_key.key.name) }}' - instance_type: t2.micro + instance_type: t3.micro state: present image_id: '{{ ecs_image_id }}' wait: yes @@ -150,24 +150,24 @@ target_type: ip register: elb_target_group_ip - # - name: create load balancer - # elb_application_lb: - # name: "{{ ecs_load_balancer_name }}" - # state: present - # scheme: internal - # security_groups: '{{ setup_sg.group_id }}' - # subnets: "{{ setup_subnet.results | map(attribute="subnet.id") }}" - # listeners: - # - Protocol: HTTP - # Port: 80 - # DefaultActions: - # - Type: forward - # TargetGroupName: "{{ ecs_target_group_name }}1" - # - Protocol: HTTP - # Port: 81 - # DefaultActions: - # - Type: forward - # TargetGroupName: "{{ ecs_target_group_name }}2" + - name: create load balancer + elb_application_lb: + name: "{{ ecs_load_balancer_name }}" + state: present + scheme: internal + security_groups: '{{ setup_sg.group_id }}' + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ ecs_target_group_name }}1" + - Protocol: HTTP + Port: 81 + DefaultActions: + - Type: forward + TargetGroupName: "{{ ecs_target_group_name }}2" - name: create task definition ecs_taskdefinition: @@ -187,8 +187,6 @@ assert: that: - not ecs_task_definition_again.changed - # FIXME: task definition should not change, will need #26752 or equivalent - ignore_errors: yes - name: obtain ECS task definition facts ecs_taskdefinition_info: @@ -240,94 +238,94 @@ # FIXME: service should not change, needs fixing ignore_errors: yes - # # FIXME: attempt to update service load balancer - # - name: update ECS service definition (expected to fail) - # ecs_service: - # state: present - # name: "{{ ecs_service_name }}" - # cluster: "{{ ecs_cluster_name }}" - # task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" - # desired_count: 1 - # deployment_configuration: "{{ ecs_service_deployment_configuration }}" - # placement_strategy: "{{ ecs_service_placement_strategy }}" - # health_check_grace_period_seconds: "{{ ecs_service_health_check_grace_period }}" - # load_balancers: - # - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" - # containerName: "{{ ecs_task_name }}" - # containerPort: "{{ ecs_task_container_port|int + 1 }}" - # role: "ecsServiceRole" - # register: update_ecs_service - # ignore_errors: yes - - # - name: assert that updating ECS load balancer failed with helpful message - # assert: - # that: - # - update_ecs_service is failed - # - "'error' not in update_ecs_service" - # - "'msg' in update_ecs_service" - - - # - name: attempt to use ECS network configuration on task definition without awsvpc network_mode - # ecs_service: - # state: present - # name: "{{ ecs_service_name }}3" - # cluster: "{{ ecs_cluster_name }}" - # task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" - # desired_count: 1 - # deployment_configuration: "{{ ecs_service_deployment_configuration }}" - # placement_strategy: "{{ ecs_service_placement_strategy }}" - # load_balancers: - # - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" - # containerName: "{{ ecs_task_name }}" - # containerPort: "{{ ecs_task_container_port }}" - # network_configuration: - # subnets: "{{ setup_subnet.results | map(attribute='subnet.id') }}" - # security_groups: - # - '{{ setup_sg.group_id }}' - # register: ecs_service_network_without_awsvpc_task - # ignore_errors: yes - - # - name: assert that using ECS network configuration with non AWSVPC task definition fails - # assert: - # that: - # - ecs_service_network_without_awsvpc_task is failed - - # - name: scale down ECS service - # ecs_service: - # state: present - # name: "{{ ecs_service_name }}" - # cluster: "{{ ecs_cluster_name }}" - # task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" - # desired_count: 0 - # deployment_configuration: "{{ ecs_service_deployment_configuration }}" - # placement_strategy: "{{ ecs_service_placement_strategy }}" - # load_balancers: - # - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" - # containerName: "{{ ecs_task_name }}" - # containerPort: "{{ ecs_task_container_port }}" - # role: "ecsServiceRole" - # register: ecs_service_scale_down - - # - name: pause to allow service to scale down - # pause: - # seconds: 60 - - # - name: delete ECS service definition - # ecs_service: - # state: absent - # name: "{{ ecs_service_name }}" - # cluster: "{{ ecs_cluster_name }}" - # register: delete_ecs_service - - # - name: assert that deleting ECS service worked - # assert: - # that: - # - delete_ecs_service.changed - - # - name: assert that deleting ECS service worked - # assert: - # that: - # - delete_ecs_service.changed + # FIXME: attempt to update service load balancer + - name: update ECS service definition (expected to fail) + ecs_service: + state: present + name: "{{ ecs_service_name }}" + cluster: "{{ ecs_cluster_name }}" + task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" + desired_count: 1 + deployment_configuration: "{{ ecs_service_deployment_configuration }}" + placement_strategy: "{{ ecs_service_placement_strategy }}" + health_check_grace_period_seconds: "{{ ecs_service_health_check_grace_period }}" + load_balancers: + - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" + containerName: "{{ ecs_task_name }}" + containerPort: "{{ ecs_task_container_port|int + 1 }}" + role: "ecsServiceRole" + register: update_ecs_service + ignore_errors: yes + + - name: assert that updating ECS load balancer failed with helpful message + assert: + that: + - update_ecs_service is failed + - "'error' not in update_ecs_service" + - "'msg' in update_ecs_service" + + + - name: attempt to use ECS network configuration on task definition without awsvpc network_mode + ecs_service: + state: present + name: "{{ ecs_service_name }}3" + cluster: "{{ ecs_cluster_name }}" + task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" + desired_count: 1 + deployment_configuration: "{{ ecs_service_deployment_configuration }}" + placement_strategy: "{{ ecs_service_placement_strategy }}" + load_balancers: + - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" + containerName: "{{ ecs_task_name }}" + containerPort: "{{ ecs_task_container_port }}" + network_configuration: + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" + security_groups: + - '{{ setup_sg.group_id }}' + register: ecs_service_network_without_awsvpc_task + ignore_errors: yes + + - name: assert that using ECS network configuration with non AWSVPC task definition fails + assert: + that: + - ecs_service_network_without_awsvpc_task is failed + + - name: scale down ECS service + ecs_service: + state: present + name: "{{ ecs_service_name }}" + cluster: "{{ ecs_cluster_name }}" + task_definition: "{{ ecs_task_name }}:{{ ecs_task_definition.taskdefinition.revision }}" + desired_count: 0 + deployment_configuration: "{{ ecs_service_deployment_configuration }}" + placement_strategy: "{{ ecs_service_placement_strategy }}" + load_balancers: + - targetGroupArn: "{{ elb_target_group_instance.target_group_arn }}" + containerName: "{{ ecs_task_name }}" + containerPort: "{{ ecs_task_container_port }}" + role: "ecsServiceRole" + register: ecs_service_scale_down + + - name: pause to allow service to scale down + pause: + seconds: 60 + + - name: delete ECS service definition + ecs_service: + state: absent + name: "{{ ecs_service_name }}" + cluster: "{{ ecs_cluster_name }}" + register: delete_ecs_service + + - name: assert that deleting ECS service worked + assert: + that: + - delete_ecs_service.changed + + - name: assert that deleting ECS service worked + assert: + that: + - delete_ecs_service.changed - name: create VPC-networked task definition with host port set to 0 (expected to fail) ecs_taskdefinition: @@ -389,7 +387,7 @@ containerName: "{{ ecs_task_name }}" containerPort: "{{ ecs_task_container_port }}" network_configuration: - subnets: "{{ setup_subnet.results | map(attribute='subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" security_groups: - '{{ setup_sg.group_id }}' register: create_ecs_service_with_vpc @@ -423,7 +421,7 @@ containerName: "{{ ecs_task_name }}" containerPort: "{{ ecs_task_container_port }}" network_configuration: - subnets: "{{ setup_subnet.results | map(attribute='subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" security_groups: - "{{ resource_prefix }}-ecs-vpc-test-sg" register: update_ecs_service_with_vpc @@ -674,7 +672,7 @@ deployment_configuration: "{{ ecs_service_deployment_configuration }}" launch_type: FARGATE network_configuration: - subnets: "{{ setup_subnet.results | map(attribute='subnet.id) }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" security_groups: - '{{ setup_sg.group_id }}' assign_public_ip: true @@ -693,7 +691,7 @@ launch_type: FARGATE count: 1 network_configuration: - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" security_groups: - '{{ setup_sg.group_id }}' assign_public_ip: true @@ -725,7 +723,7 @@ tag_key: tag_value tag_key2: tag_value2 network_configuration: - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" security_groups: - '{{ setup_sg.group_id }}' assign_public_ip: true @@ -752,7 +750,7 @@ tag_key: tag_value tag_key2: tag_value2 network_configuration: - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" security_groups: - '{{ setup_sg.group_id }}' assign_public_ip: true @@ -767,7 +765,7 @@ launch_type: FARGATE count: 1 network_configuration: - subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}" + subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}" security_groups: - '{{ setup_sg.group_id }}' assign_public_ip: false @@ -857,8 +855,6 @@ ignore_errors: yes register: ecs_service_scale_down - - - name: scale down scheduling_strategy service ecs_service: name: "{{ ecs_service_name }}-replica" From 24a9d4799a2810bba79c9f662b57a92f84ef39af Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Tue, 11 May 2021 23:34:50 +0200 Subject: [PATCH 3/4] Add more casts to int Signed-off-by: Alina Buzachis --- plugins/modules/ecs_taskdefinition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/ecs_taskdefinition.py b/plugins/modules/ecs_taskdefinition.py index 13a68ec0d66..5f144fd4763 100644 --- a/plugins/modules/ecs_taskdefinition.py +++ b/plugins/modules/ecs_taskdefinition.py @@ -829,12 +829,12 @@ def main(): if linux_param == 'maxSwap' and launch_type == 'FARGATE': module.fail_json(msg='maxSwap parameter is not supported with the FARGATE launch type.') - elif linux_param == 'maxSwap' and container['linuxParameters']['maxSwap'] < 0: + elif linux_param == 'maxSwap' and int(container['linuxParameters']['maxSwap']) < 0: module.fail_json(msg='Accepted values for maxSwap are 0 or any positive integer.') if ( linux_param == 'swappiness' and - (container['linuxParameters']['swappiness'] < 0 or container['linuxParameters']['swappiness'] > 100) + (int(container['linuxParameters']['swappiness']) < 0 or int(container['linuxParameters']['swappiness']) > 100) ): module.fail_json(msg='Accepted values for swappiness are whole numbers between 0 and 100.') From 5ec234e1562098879c7098b5e4c6c12a38c32cdd Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Tue, 13 Jul 2021 14:21:31 +0200 Subject: [PATCH 4/4] Add changelog fragment Signed-off-by: Alina Buzachis --- changelogs/fragments/574-ecs_taskdefinition-improvement.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelogs/fragments/574-ecs_taskdefinition-improvement.yml diff --git a/changelogs/fragments/574-ecs_taskdefinition-improvement.yml b/changelogs/fragments/574-ecs_taskdefinition-improvement.yml new file mode 100644 index 00000000000..c8667401464 --- /dev/null +++ b/changelogs/fragments/574-ecs_taskdefinition-improvement.yml @@ -0,0 +1,3 @@ +bugfixes: +- ecs_taskdefinition - ensure cast to integer (https://github.com/ansible-collections/community.aws/pull/574). +- ecs_taskdefinition - fix idempotency (https://github.com/ansible-collections/community.aws/pull/574).