docker_swarm_service: Add command option (#50984)

* Add command option

* Fix test task name

* Changelog fragment

* Fix indendation

* Add version_added

* Better command description

* Test passing command as list

* Handle invalid command types

* Cleaner command type checking

* Check that all items in command list are strings

* Better error about command list items

* Better type checking errors

* Add tests for command type checking

* Update command tests

* Fix messed up rebase
pull/51148/head
Hannes Ljungberg 6 years ago committed by ansibot
parent 9c44dc371b
commit e3f61f4480

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

@ -41,6 +41,12 @@ options:
description: description:
- List comprised of the command and the arguments to be run inside - List comprised of the command and the arguments to be run inside
- the container - the container
command:
required: false
description:
- Command to execute when the container starts.
A command may be either a string or a list or a list of strings.
version_added: 2.8
constraints: constraints:
required: false required: false
default: [] default: []
@ -511,6 +517,7 @@ EXAMPLES = '''
''' '''
import time import time
import shlex
import operator import operator
from ansible.module_utils.docker_common import ( from ansible.module_utils.docker_common import (
DockerBaseClass, DockerBaseClass,
@ -518,6 +525,7 @@ from ansible.module_utils.docker_common import (
DifferenceTracker, DifferenceTracker,
) )
from ansible.module_utils.basic import human_to_bytes from ansible.module_utils.basic import human_to_bytes
from ansible.module_utils.six import string_types
from ansible.module_utils._text import to_text from ansible.module_utils._text import to_text
try: try:
@ -532,6 +540,7 @@ class DockerService(DockerBaseClass):
def __init__(self): def __init__(self):
super(DockerService, self).__init__() super(DockerService, self).__init__()
self.image = "" self.image = ""
self.command = None
self.args = [] self.args = []
self.endpoint_mode = "vip" self.endpoint_mode = "vip"
self.dns = [] self.dns = []
@ -579,6 +588,7 @@ class DockerService(DockerBaseClass):
'mounts': self.mounts, 'mounts': self.mounts,
'configs': self.configs, 'configs': self.configs,
'networks': self.networks, 'networks': self.networks,
'command': self.command,
'args': self.args, 'args': self.args,
'tty': self.tty, 'tty': self.tty,
'dns': self.dns, 'dns': self.dns,
@ -646,6 +656,35 @@ class DockerService(DockerBaseClass):
s.update_order = ap['update_order'] s.update_order = ap['update_order']
s.user = ap['user'] s.user = ap['user']
s.command = ap['command']
if isinstance(s.command, string_types):
s.command = shlex.split(s.command)
elif isinstance(s.command, list):
invalid_items = [
(index, item)
for index, item in enumerate(s.command)
if not isinstance(item, string_types)
]
if invalid_items:
errors = ', '.join(
[
'%s (%s) at index %s' % (item, type(item), index)
for index, item in invalid_items
]
)
raise Exception(
'All items in a command list need to be strings. '
'Check quoting. Invalid items: %s.'
% errors
)
s.command = ap['command']
elif s.command is not None:
raise ValueError(
'Invalid type for command %s (%s). '
'Only string or list allowed. Check quoting.'
% (s.command, type(s.command))
)
if ap['force_update']: if ap['force_update']:
s.force_update = int(str(time.time()).replace('.', '')) s.force_update = int(str(time.time()).replace('.', ''))
@ -738,6 +777,8 @@ class DockerService(DockerBaseClass):
needs_rebuild = True needs_rebuild = True
if self.replicas != os.replicas: if self.replicas != os.replicas:
differences.add('replicas', parameter=self.replicas, active=os.replicas) differences.add('replicas', parameter=self.replicas, active=os.replicas)
if self.command is not None and self.command != os.command:
differences.add('command', parameter=self.command, active=os.command)
if self.args != os.args: if self.args != os.args:
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:
@ -866,17 +907,24 @@ class DockerService(DockerBaseClass):
) )
) )
dns_config = types.DNSConfig(
nameservers=self.dns,
search=self.dns_search,
options=self.dns_options
)
cspec = types.ContainerSpec( cspec = types.ContainerSpec(
image=self.image, image=self.image,
user=self.user, command=self.command,
dns_config=types.DNSConfig(nameservers=self.dns, search=self.dns_search, options=self.dns_options),
args=self.args, args=self.args,
env=self.env,
tty=self.tty,
hostname=self.hostname, hostname=self.hostname,
env=self.env,
user=self.user,
labels=self.container_labels, labels=self.container_labels,
mounts=mounts, mounts=mounts,
secrets=secrets, secrets=secrets,
tty=self.tty,
dns_config=dns_config,
configs=configs configs=configs
) )
@ -983,6 +1031,7 @@ class DockerServiceManager():
ds.image = task_template_data['ContainerSpec']['Image'] ds.image = task_template_data['ContainerSpec']['Image']
ds.user = task_template_data['ContainerSpec'].get('User', 'root') ds.user = task_template_data['ContainerSpec'].get('User', 'root')
ds.env = task_template_data['ContainerSpec'].get('Env', []) ds.env = task_template_data['ContainerSpec'].get('Env', [])
ds.command = task_template_data['ContainerSpec'].get('Command')
ds.args = task_template_data['ContainerSpec'].get('Args', []) ds.args = task_template_data['ContainerSpec'].get('Args', [])
ds.update_delay = update_config_data['Delay'] ds.update_delay = update_config_data['Delay']
ds.update_parallelism = update_config_data['Parallelism'] ds.update_parallelism = update_config_data['Parallelism']
@ -1216,6 +1265,7 @@ def main():
configs=dict(default=None, type='list'), configs=dict(default=None, type='list'),
secrets=dict(default=[], type='list'), secrets=dict(default=[], type='list'),
networks=dict(default=[], type='list'), networks=dict(default=[], type='list'),
command=dict(default=None, type='raw'),
args=dict(default=[], type='list'), args=dict(default=[], type='list'),
env=dict(default=[], type='list'), env=dict(default=[], type='list'),
force_update=dict(default=False, type='bool'), force_update=dict(default=False, type='bool'),

@ -209,6 +209,74 @@
- constraints_2 is not changed - constraints_2 is not changed
- constraints_3 is changed - constraints_3 is changed
####################################################################
## command #########################################################
####################################################################
- name: command
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
command: '/bin/sh -v -c "sleep 10m"'
register: command_1
- name: command (idempotency)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
command: '/bin/sh -v -c "sleep 10m"'
register: command_2
- name: command (less parameters)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
command: '/bin/sh -c "sleep 10m"'
register: command_3
- name: command (as list)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
command:
- "/bin/sh"
- "-c"
- "sleep 10m"
register: command_4
- name: command (string failure)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
command: yes
register: command_5
ignore_errors: yes
- name: command (list failure)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
command:
- "/bin/sh"
- yes
register: command_6
ignore_errors: yes
- name: cleanup
docker_swarm_service:
name: "{{ service_name }}"
state: absent
diff: no
- assert:
that:
- command_1 is changed
- command_2 is not changed
- command_3 is changed
- command_4 is not changed
- command_5 is failed
- command_6 is failed
#################################################################### ####################################################################
## container_labels ################################################ ## container_labels ################################################
#################################################################### ####################################################################

@ -5,6 +5,7 @@ service_expected_output:
configs: null configs: null
constraints: [] constraints: []
container_labels: {} container_labels: {}
command: null
dns: [] dns: []
dns_options: [] dns_options: []
dns_search: [] dns_search: []

Loading…
Cancel
Save