docker_swarm_service: Add placement_preferences option (#51082)

* Add placement_preferences option

* Add changelog fragment

* Python 2.6 compat

Python 2.6 compat

* Cleaner check

* Better description

* Don’t compare placement_preferences if None

* Add placement_preferences example
This commit is contained in:
Hannes Ljungberg 2019-01-21 20:55:26 +01:00 committed by Brian Coca
parent 552cb1f6b9
commit 393bf5e4b1
4 changed files with 82 additions and 3 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- "docker_swarm_service - Added support for ``placement_preferences`` parameter."

View file

@ -47,6 +47,13 @@ options:
description: description:
- List of the service constraints. - List of the service constraints.
- Maps docker service --constraint option. - Maps docker service --constraint option.
placement_preferences:
required: false
type: list
description:
- List of the placement preferences as key value pairs.
- Maps docker service C(--placement-pref) option.
version_added: 2.8
hostname: hostname:
required: false required: false
default: "" default: ""
@ -495,6 +502,12 @@ EXAMPLES = '''
docker_swarm_service: docker_swarm_service:
name: myservice name: myservice
state: absent state: absent
- name: set placement preferences
docker_swarm_service:
name: myservice
image: alpine:edge
placement_preferences:
- spread: "node.labels.mylabel"
''' '''
import time import time
@ -518,7 +531,6 @@ except Exception:
class DockerService(DockerBaseClass): class DockerService(DockerBaseClass):
def __init__(self): def __init__(self):
super(DockerService, self).__init__() super(DockerService, self).__init__()
self.constraints = []
self.image = "" self.image = ""
self.args = [] self.args = []
self.endpoint_mode = "vip" self.endpoint_mode = "vip"
@ -545,6 +557,8 @@ class DockerService(DockerBaseClass):
self.constraints = [] self.constraints = []
self.networks = [] self.networks = []
self.publish = [] self.publish = []
self.constraints = []
self.placement_preferences = None
self.replicas = -1 self.replicas = -1
self.service_id = False self.service_id = False
self.service_version = False self.service_version = False
@ -577,6 +591,7 @@ class DockerService(DockerBaseClass):
'log_driver_options': self.log_driver_options, 'log_driver_options': self.log_driver_options,
'publish': self.publish, 'publish': self.publish,
'constraints': self.constraints, 'constraints': self.constraints,
'placement_preferences': self.placement_preferences,
'labels': self.labels, 'labels': self.labels,
'container_labels': self.container_labels, 'container_labels': self.container_labels,
'mode': self.mode, 'mode': self.mode,
@ -601,6 +616,7 @@ class DockerService(DockerBaseClass):
def from_ansible_params(ap, old_service): def from_ansible_params(ap, old_service):
s = DockerService() s = DockerService()
s.constraints = ap['constraints'] s.constraints = ap['constraints']
s.placement_preferences = ap['placement_preferences']
s.image = ap['image'] s.image = ap['image']
s.args = ap['args'] s.args = ap['args']
s.endpoint_mode = ap['endpoint_mode'] s.endpoint_mode = ap['endpoint_mode']
@ -726,6 +742,8 @@ class DockerService(DockerBaseClass):
differences.add('args', parameter=self.args, active=os.args) differences.add('args', parameter=self.args, active=os.args)
if self.constraints != os.constraints: if self.constraints != os.constraints:
differences.add('constraints', parameter=self.constraints, active=os.constraints) differences.add('constraints', parameter=self.constraints, active=os.constraints)
if self.placement_preferences is not None and self.placement_preferences != os.placement_preferences:
differences.add('placement_preferences', parameter=self.placement_preferences, active=os.placement_preferences)
if self.labels != os.labels: if self.labels != os.labels:
differences.add('labels', parameter=self.labels, active=os.labels) differences.add('labels', parameter=self.labels, active=os.labels)
if self.limit_cpu != os.limit_cpu: if self.limit_cpu != os.limit_cpu:
@ -864,7 +882,14 @@ class DockerService(DockerBaseClass):
log_driver = types.DriverConfig(name=self.log_driver, options=self.log_driver_options) log_driver = types.DriverConfig(name=self.log_driver, options=self.log_driver_options)
placement = types.Placement(constraints=self.constraints) placement = types.Placement(
constraints=self.constraints,
preferences=[
{key.title(): {"SpreadDescriptor": value}}
for preference in self.placement_preferences
for key, value in preference.items()
] if self.placement_preferences else None,
)
restart_policy = types.RestartPolicy( restart_policy = types.RestartPolicy(
condition=self.restart_policy, condition=self.restart_policy,
@ -979,7 +1004,17 @@ class DockerServiceManager():
ds.hostname = task_template_data['ContainerSpec'].get('Hostname', '') ds.hostname = task_template_data['ContainerSpec'].get('Hostname', '')
ds.tty = task_template_data['ContainerSpec'].get('TTY', False) ds.tty = task_template_data['ContainerSpec'].get('TTY', False)
if 'Placement' in task_template_data.keys(): if 'Placement' in task_template_data.keys():
ds.constraints = task_template_data['Placement'].get('Constraints', []) placement = task_template_data['Placement']
ds.constraints = placement.get('Constraints', [])
placement_preferences = []
for preference in placement.get('Preferences', []):
placement_preferences.append(
dict(
(key.lower(), value["SpreadDescriptor"])
for key, value in preference.items()
)
)
ds.placement_preferences = placement_preferences or None
restart_policy_data = task_template_data.get('RestartPolicy', None) restart_policy_data = task_template_data.get('RestartPolicy', None)
if restart_policy_data: if restart_policy_data:
@ -1193,6 +1228,7 @@ def main():
mode=dict(type='str', required=False, choices=('ingress', 'host')), mode=dict(type='str', required=False, choices=('ingress', 'host')),
)), )),
constraints=dict(default=[], type='list'), constraints=dict(default=[], type='list'),
placement_preferences=dict(default=None, type='list'),
tty=dict(default=False, type='bool'), tty=dict(default=False, type='bool'),
dns=dict(default=[], type='list'), dns=dict(default=[], type='list'),
dns_search=dict(default=[], type='list'), dns_search=dict(default=[], type='list'),

View file

@ -950,6 +950,46 @@
- networks_2 is not changed - networks_2 is not changed
- networks_3 is changed - networks_3 is changed
####################################################################
## placement_preferences ###########################################
####################################################################
- name: placement_preferences
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
placement_preferences:
- spread: "node.labels.test"
register: placement_preferences_1
- name: placement_preferences (idempotency)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
placement_preferences:
- spread: "node.labels.test"
register: placement_preferences_2
- name: placement_preferences (change)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
placement_preferences:
- spread: "node.labels.test2"
register: placement_preferences_3
- name: cleanup
docker_swarm_service:
name: "{{ service_name }}"
state: absent
diff: no
- assert:
that:
- placement_preferences_1 is changed
- placement_preferences_2 is not changed
- placement_preferences_3 is changed
#################################################################### ####################################################################
## publish ######################################################### ## publish #########################################################
#################################################################### ####################################################################

View file

@ -21,6 +21,7 @@ service_expected_output:
mode: global mode: global
mounts: [] mounts: []
networks: [] networks: []
placement_preferences: null
publish: publish:
- {mode: null, protocol: tcp, published_port: 60001, target_port: 60001} - {mode: null, protocol: tcp, published_port: 60001, target_port: 60001}
- {mode: null, protocol: udp, published_port: 60001, target_port: 60001} - {mode: null, protocol: udp, published_port: 60001, target_port: 60001}