Ecs service force new deployment (#47983)

* Support UpdateService forceNewDeployment in ecs_service module

* Force update to be called if force_new_deployment set

* Fixes for review

* Add force_new_deployment option to ecs_service.py

cherrypicks changes from via/ansible
Adds tests for pull request #42518
fixes backwards compatability with boto<1.8.4

* change version_added to 2.8 for force_new_deployment

* remove extra lines from test

* remove more unnecessary whitespace
pull/49083/head
Tad Merchant 6 years ago committed by Will Thames
parent 3143abc8dc
commit 4b2356ff55

@ -82,6 +82,12 @@ options:
- The number of times to check that the service is available - The number of times to check that the service is available
required: false required: false
default: 10 default: 10
force_new_deployment:
description:
- Force deployment of service even if there are no changes
required: false
version_added: 2.8
type: bool
deployment_configuration: deployment_configuration:
description: description:
- Optional parameters that control the deployment_configuration; format is '{"maximum_percent":<integer>, "minimum_healthy_percent":<integer>} - Optional parameters that control the deployment_configuration; format is '{"maximum_percent":<integer>, "minimum_healthy_percent":<integer>}
@ -412,18 +418,20 @@ class EcsServiceManager:
return self.jsonize(response['service']) return self.jsonize(response['service'])
def update_service(self, service_name, cluster_name, task_definition, def update_service(self, service_name, cluster_name, task_definition,
desired_count, deployment_configuration, network_configuration, health_check_grace_period_seconds): desired_count, deployment_configuration, network_configuration,
health_check_grace_period_seconds, force_new_deployment):
params = dict( params = dict(
cluster=cluster_name, cluster=cluster_name,
service=service_name, service=service_name,
taskDefinition=task_definition, taskDefinition=task_definition,
desiredCount=desired_count, desiredCount=desired_count,
deploymentConfiguration=deployment_configuration deploymentConfiguration=deployment_configuration)
)
if network_configuration: if network_configuration:
params['networkConfiguration'] = network_configuration params['networkConfiguration'] = network_configuration
if self.health_check_setable(params): if self.health_check_setable(params):
params['healthCheckGracePeriodSeconds'] = health_check_grace_period_seconds params['healthCheckGracePeriodSeconds'] = health_check_grace_period_seconds
if force_new_deployment:
params['forceNewDeployment'] = force_new_deployment
response = self.ecs.update_service(**params) response = self.ecs.update_service(**params)
return self.jsonize(response['service']) return self.jsonize(response['service'])
@ -472,6 +480,7 @@ def main():
role=dict(required=False, default='', type='str'), role=dict(required=False, default='', type='str'),
delay=dict(required=False, type='int', default=10), delay=dict(required=False, type='int', default=10),
repeat=dict(required=False, type='int', default=10), repeat=dict(required=False, type='int', default=10),
force_new_deployment=dict(required=False, default=False, type='bool'),
deployment_configuration=dict(required=False, default={}, type='dict'), deployment_configuration=dict(required=False, default={}, type='dict'),
placement_constraints=dict(required=False, default=[], type='list'), placement_constraints=dict(required=False, default=[], type='list'),
placement_strategy=dict(required=False, default=[], type='list'), placement_strategy=dict(required=False, default=[], type='list'),
@ -513,6 +522,9 @@ def main():
if module.params['launch_type']: if module.params['launch_type']:
if not module.botocore_at_least('1.8.4'): 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') module.fail_json(msg='botocore needs to be version 1.8.4 or higher to use launch_type')
if module.params['force_new_deployment']:
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 force_new_deployment')
if module.params['state'] == 'present': if module.params['state'] == 'present':
@ -520,7 +532,9 @@ def main():
update = False update = False
if existing and 'status' in existing and existing['status'] == "ACTIVE": if existing and 'status' in existing and existing['status'] == "ACTIVE":
if service_mgr.is_matching_service(module.params, existing): if module.params['force_new_deployment']:
update = True
elif service_mgr.is_matching_service(module.params, existing):
matching = True matching = True
results['service'] = existing results['service'] = existing
else: else:
@ -552,8 +566,8 @@ def main():
module.params['desired_count'], module.params['desired_count'],
deploymentConfiguration, deploymentConfiguration,
network_configuration, network_configuration,
module.params['health_check_grace_period_seconds'] module.params['health_check_grace_period_seconds'],
) module.params['force_new_deployment'])
else: else:
try: try:
response = service_mgr.create_service(module.params['name'], response = service_mgr.create_service(module.params['name'],

@ -0,0 +1,108 @@
- hosts: localhost
connection: local
vars:
resource_prefix: 'ansible-testing-fnd'
tasks:
- block:
- name: set up aws connection info
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: True
- name: create ecs cluster
ecs_cluster:
name: "{{ resource_prefix }}"
state: present
<<: *aws_connection_info
- name: create ecs_taskdefinition
ecs_taskdefinition:
containers:
- name: my_container
image: ubuntu
memory: 128
family: "{{ resource_prefix }}"
state: present
<<: *aws_connection_info
register: ecs_taskdefinition_creation
- name: create ecs_service
ecs_service:
name: "{{ resource_prefix }}"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
state: present
<<: *aws_connection_info
register: ecs_service_creation
- name: ecs_service works fine even when older botocore is used
assert:
that:
- ecs_service_creation.changed
- name: create ecs_service using force_new_deployment
ecs_service:
name: "{{ resource_prefix }}"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
force_new_deployment: true
state: present
<<: *aws_connection_info
register: ecs_service_creation_force_new_deploy
ignore_errors: yes
- name: check that module returns success
assert:
that:
- ecs_service_creation_force_new_deploy.changed
always:
- name: scale down ecs service
ecs_service:
name: "{{ resource_prefix }}"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 0
state: present
<<: *aws_connection_info
ignore_errors: yes
- name: pause to wait for scale down
pause:
seconds: 30
- name: remove ecs service
ecs_service:
name: "{{ resource_prefix }}"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
state: absent
<<: *aws_connection_info
ignore_errors: yes
- name: remove ecs task definition
ecs_taskdefinition:
containers:
- name: my_container
image: ubuntu
memory: 128
family: "{{ resource_prefix }}"
revision: "{{ ecs_taskdefinition_creation.taskdefinition.revision }}"
state: absent
<<: *aws_connection_info
ignore_errors: yes
- name: remove ecs cluster
ecs_cluster:
name: "{{ resource_prefix }}"
state: absent
<<: *aws_connection_info
ignore_errors: yes

@ -0,0 +1,109 @@
- hosts: localhost
connection: local
vars:
resource_prefix: 'ansible-testing-fndf'
tasks:
- block:
- name: set up aws connection info
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: True
- name: create ecs cluster
ecs_cluster:
name: "{{ resource_prefix }}"
state: present
<<: *aws_connection_info
- name: create ecs_taskdefinition
ecs_taskdefinition:
containers:
- name: my_container
image: ubuntu
memory: 128
family: "{{ resource_prefix }}"
state: present
<<: *aws_connection_info
register: ecs_taskdefinition_creation
- name: create ecs_service
ecs_service:
name: "{{ resource_prefix }}"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
state: present
<<: *aws_connection_info
register: ecs_service_creation
- name: ecs_service works fine even when older botocore is used
assert:
that:
- ecs_service_creation.changed
- name: create ecs_service using force_new_deployment
ecs_service:
name: "{{ resource_prefix }}"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
force_new_deployment: true
state: present
<<: *aws_connection_info
register: ecs_service_creation_force_new_deploy
ignore_errors: yes
- name: check that graceful failure message is returned from ecs_service
assert:
that:
- ecs_service_creation_force_new_deploy.failed
- 'ecs_service_creation_force_new_deploy.msg == "botocore needs to be version 1.8.4 or higher to use force_new_deployment"'
always:
- name: scale down ecs service
ecs_service:
name: "{{ resource_prefix }}"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 0
state: present
<<: *aws_connection_info
ignore_errors: yes
- name: pause to wait for scale down
pause:
seconds: 30
- name: remove ecs service
ecs_service:
name: "{{ resource_prefix }}"
cluster: "{{ resource_prefix }}"
task_definition: "{{ resource_prefix }}"
desired_count: 1
state: absent
<<: *aws_connection_info
ignore_errors: yes
- name: remove ecs task definition
ecs_taskdefinition:
containers:
- name: my_container
image: ubuntu
memory: 128
family: "{{ resource_prefix }}"
revision: "{{ ecs_taskdefinition_creation.taskdefinition.revision }}"
state: absent
<<: *aws_connection_info
ignore_errors: yes
- name: remove ecs cluster
ecs_cluster:
name: "{{ resource_prefix }}"
state: absent
<<: *aws_connection_info
ignore_errors: yes

@ -25,6 +25,20 @@ source "${MYTMPDIR}/botocore-1.7.44/bin/activate"
$PYTHON -m pip install 'botocore>=1.7.44,<1.8.4' boto3 $PYTHON -m pip install 'botocore>=1.7.44,<1.8.4' boto3
ansible-playbook -i ../../inventory -e @../../integration_config.yml -e @../../cloud-config-aws.yml -v playbooks/network_assign_public_ip_fail.yml "$@" ansible-playbook -i ../../inventory -e @../../integration_config.yml -e @../../cloud-config-aws.yml -v playbooks/network_assign_public_ip_fail.yml "$@"
# Test graceful failure for force new deployment #42518
# applies for botocore < 1.8.4
virtualenv --system-site-packages --python "${PYTHON}" "${MYTMPDIR}/botocore-1.8.4"
source "${MYTMPDIR}/botocore-1.8.4/bin/activate"
$PYTHON -m pip install 'botocore>=1.7.44,<1.8.4' boto3
ansible-playbook -i ../../inventory -e @../../integration_config.yml -e @../../cloud-config-aws.yml -v playbooks/network_force_new_deployment_fail.yml "$@"
# Test force new deployment #42518
# applies for botocore < 1.8.4
virtualenv --system-site-packages --python "${PYTHON}" "${MYTMPDIR}/botocore-1.8.5"
source "${MYTMPDIR}/botocore-1.8.5/bin/activate"
$PYTHON -m pip install 'botocore>1.8.4' boto3
ansible-playbook -i ../../inventory -e @../../integration_config.yml -e @../../cloud-config-aws.yml -v playbooks/network_force_new_deployment.yml "$@"
# Run full test suite # Run full test suite
virtualenv --system-site-packages --python "${PYTHON}" "${MYTMPDIR}/botocore-recent" virtualenv --system-site-packages --python "${PYTHON}" "${MYTMPDIR}/botocore-recent"
source "${MYTMPDIR}/botocore-recent/bin/activate" source "${MYTMPDIR}/botocore-recent/bin/activate"

Loading…
Cancel
Save