mirror of
https://github.com/ansible-collections/community.docker.git
synced 2026-03-30 08:43:58 +00:00
docker_compose_v2: allow to specify pull policy; parse pull events; improve error handling; always return stderr (#746)
* Add pull option for 'docker compose up'. * Improve dry-mode event parsing, and also parse pull-related events. * Improve error handling, and add first tests. * Fix action status documentation. * Add more tests. * Always return stderr. This makes debugging misbehavior a lot easier since you can see what 'docker compose' actually returned. * Reformat existing tests.
This commit is contained in:
parent
4a5293503e
commit
eed89f32eb
@ -69,6 +69,20 @@ options:
|
|||||||
- stopped
|
- stopped
|
||||||
- restarted
|
- restarted
|
||||||
- present
|
- present
|
||||||
|
pull:
|
||||||
|
description:
|
||||||
|
- Whether to pull images before running. This is used when C(docker compose up) is ran.
|
||||||
|
- V(always) ensures that the images are always pulled, even when already present on the Docker daemon.
|
||||||
|
- V(missing) only pulls them when they are not present on the Docker daemon.
|
||||||
|
- V(never) never pulls images. If they are not present, the module will fail when trying to create the containers that need them.
|
||||||
|
- V(policy) use the C(pull_policy) defined for the service to figure out what to do.
|
||||||
|
type: str
|
||||||
|
choices:
|
||||||
|
- always
|
||||||
|
- missing
|
||||||
|
- never
|
||||||
|
- policy
|
||||||
|
default: policy
|
||||||
dependencies:
|
dependencies:
|
||||||
description:
|
description:
|
||||||
- When O(state) is V(present) or V(restarted), specify whether or not to include linked services.
|
- When O(state) is V(present) or V(restarted), specify whether or not to include linked services.
|
||||||
@ -90,8 +104,8 @@ options:
|
|||||||
- Use with O(state=absent) to remove all images or only local images.
|
- Use with O(state=absent) to remove all images or only local images.
|
||||||
type: str
|
type: str
|
||||||
choices:
|
choices:
|
||||||
- 'all'
|
- all
|
||||||
- 'local'
|
- local
|
||||||
remove_volumes:
|
remove_volumes:
|
||||||
description:
|
description:
|
||||||
- Use with O(state=absent) to remove data volumes.
|
- Use with O(state=absent) to remove data volumes.
|
||||||
@ -346,10 +360,12 @@ actions:
|
|||||||
type: str
|
type: str
|
||||||
sample: container
|
sample: container
|
||||||
choices:
|
choices:
|
||||||
- network
|
|
||||||
- image
|
|
||||||
- volume
|
|
||||||
- container
|
- container
|
||||||
|
- image
|
||||||
|
- network
|
||||||
|
- service
|
||||||
|
- unknown
|
||||||
|
- volume
|
||||||
id:
|
id:
|
||||||
description:
|
description:
|
||||||
- The ID of the resource that was changed.
|
- The ID of the resource that was changed.
|
||||||
@ -359,16 +375,17 @@ actions:
|
|||||||
description:
|
description:
|
||||||
- The status change that happened.
|
- The status change that happened.
|
||||||
type: str
|
type: str
|
||||||
sample: Created
|
sample: Creating
|
||||||
choices:
|
choices:
|
||||||
- Started
|
- Starting
|
||||||
- Exited
|
- Exiting
|
||||||
- Restarted
|
- Restarting
|
||||||
- Created
|
- Creating
|
||||||
- Stopped
|
- Stopping
|
||||||
- Killed
|
- Killing
|
||||||
- Removed
|
- Removing
|
||||||
- Recreated
|
- Recreating
|
||||||
|
- Pulling
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@ -377,6 +394,7 @@ import traceback
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_native
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
|
from ansible.module_utils.six.moves import shlex_quote
|
||||||
|
|
||||||
from ansible_collections.community.docker.plugins.module_utils.common_cli import (
|
from ansible_collections.community.docker.plugins.module_utils.common_cli import (
|
||||||
AnsibleModuleDockerClient,
|
AnsibleModuleDockerClient,
|
||||||
@ -401,6 +419,8 @@ DOCKER_STATUS_DONE = frozenset((
|
|||||||
'Removed',
|
'Removed',
|
||||||
# An extra, specific to containers
|
# An extra, specific to containers
|
||||||
'Recreated',
|
'Recreated',
|
||||||
|
# Extras for pull events
|
||||||
|
'Pulled',
|
||||||
))
|
))
|
||||||
DOCKER_STATUS_WORKING = frozenset((
|
DOCKER_STATUS_WORKING = frozenset((
|
||||||
'Creating',
|
'Creating',
|
||||||
@ -412,18 +432,26 @@ DOCKER_STATUS_WORKING = frozenset((
|
|||||||
'Removing',
|
'Removing',
|
||||||
# An extra, specific to containers
|
# An extra, specific to containers
|
||||||
'Recreate',
|
'Recreate',
|
||||||
|
# Extras for pull events
|
||||||
|
'Pulling',
|
||||||
|
))
|
||||||
|
DOCKER_STATUS_PULL = frozenset((
|
||||||
|
'Pulled',
|
||||||
|
'Pulling',
|
||||||
))
|
))
|
||||||
DOCKER_STATUS_ERROR = frozenset((
|
DOCKER_STATUS_ERROR = frozenset((
|
||||||
'Error',
|
'Error',
|
||||||
))
|
))
|
||||||
DOCKER_STATUS = frozenset(DOCKER_STATUS_DONE | DOCKER_STATUS_WORKING | DOCKER_STATUS_ERROR)
|
DOCKER_STATUS = frozenset(DOCKER_STATUS_DONE | DOCKER_STATUS_WORKING | DOCKER_STATUS_PULL | DOCKER_STATUS_ERROR)
|
||||||
|
|
||||||
|
|
||||||
class ResourceType(object):
|
class ResourceType(object):
|
||||||
|
UNKNOWN = "unknown"
|
||||||
NETWORK = "network"
|
NETWORK = "network"
|
||||||
IMAGE = "image"
|
IMAGE = "image"
|
||||||
VOLUME = "volume"
|
VOLUME = "volume"
|
||||||
CONTAINER = "container"
|
CONTAINER = "container"
|
||||||
|
SERVICE = "service"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_docker_compose_event(cls, resource_type):
|
def from_docker_compose_event(cls, resource_type):
|
||||||
@ -442,6 +470,8 @@ ResourceEvent = namedtuple(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_DRY_RUN_MARKER = 'DRY-RUN MODE -'
|
||||||
|
|
||||||
_RE_RESOURCE_EVENT = re.compile(
|
_RE_RESOURCE_EVENT = re.compile(
|
||||||
r'^'
|
r'^'
|
||||||
r'\s*'
|
r'\s*'
|
||||||
@ -454,18 +484,26 @@ _RE_RESOURCE_EVENT = re.compile(
|
|||||||
r'$'
|
r'$'
|
||||||
)
|
)
|
||||||
|
|
||||||
_RE_RESOURCE_EVENT_DRY_RUN = re.compile(
|
_RE_PULL_EVENT = re.compile(
|
||||||
r'^'
|
r'^'
|
||||||
r'\s*'
|
r'\s*'
|
||||||
r'DRY-RUN MODE -'
|
r'(?P<service>\S+)'
|
||||||
r'\s+'
|
r'\s+'
|
||||||
r'(?P<resource_type>Network|Image|Volume|Container)'
|
r'(?P<status>%s)'
|
||||||
r'\s+'
|
|
||||||
r'(?P<resource_id>\S+)'
|
|
||||||
r'\s+'
|
|
||||||
r'(?P<status>\S(?:|.*\S))'
|
|
||||||
r'\s*'
|
r'\s*'
|
||||||
r'$'
|
r'$'
|
||||||
|
% '|'.join(re.escape(status) for status in DOCKER_STATUS_PULL)
|
||||||
|
)
|
||||||
|
|
||||||
|
_RE_ERROR_EVENT = re.compile(
|
||||||
|
r'^'
|
||||||
|
r'\s*'
|
||||||
|
r'(?P<resource_id>\S+)'
|
||||||
|
r'\s+'
|
||||||
|
r'(?P<status>%s)'
|
||||||
|
r'\s*'
|
||||||
|
r'$'
|
||||||
|
% '|'.join(re.escape(status) for status in DOCKER_STATUS_ERROR)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -482,6 +520,7 @@ class ContainerManager(DockerBaseClass):
|
|||||||
self.profiles = parameters['profiles']
|
self.profiles = parameters['profiles']
|
||||||
self.state = parameters['state']
|
self.state = parameters['state']
|
||||||
self.dependencies = parameters['dependencies']
|
self.dependencies = parameters['dependencies']
|
||||||
|
self.pull = parameters['pull']
|
||||||
self.recreate = parameters['recreate']
|
self.recreate = parameters['recreate']
|
||||||
self.remove_images = parameters['remove_images']
|
self.remove_images = parameters['remove_images']
|
||||||
self.remove_volumes = parameters['remove_volumes']
|
self.remove_volumes = parameters['remove_volumes']
|
||||||
@ -566,34 +605,98 @@ class ContainerManager(DockerBaseClass):
|
|||||||
|
|
||||||
result['containers'] = self.list_containers()
|
result['containers'] = self.list_containers()
|
||||||
result['images'] = self.list_images()
|
result['images'] = self.list_images()
|
||||||
|
if not result.get('failed'):
|
||||||
|
# Only return stdout and stderr if it's not empty
|
||||||
|
for res in ('stdout', 'stderr'):
|
||||||
|
if result.get(res) == '':
|
||||||
|
result.pop(res)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def parse_events(self, stderr, dry_run=False):
|
def parse_events(self, stderr, dry_run=False):
|
||||||
events = []
|
events = []
|
||||||
|
error_event = None
|
||||||
for line in stderr.splitlines():
|
for line in stderr.splitlines():
|
||||||
line = to_native(line.strip())
|
line = to_native(line.strip())
|
||||||
match = (_RE_RESOURCE_EVENT_DRY_RUN if dry_run else _RE_RESOURCE_EVENT).match(line)
|
if not line:
|
||||||
|
continue
|
||||||
|
if dry_run:
|
||||||
|
if line.startswith(_DRY_RUN_MARKER):
|
||||||
|
line = line[len(_DRY_RUN_MARKER):].lstrip()
|
||||||
|
elif error_event is None:
|
||||||
|
# This could be a bug, a change of docker compose's output format, ...
|
||||||
|
# Tell the user to report it to us :-)
|
||||||
|
self.client.warn(
|
||||||
|
'Event line is missing dry-run mode marker: {0!r}. Please report this at '
|
||||||
|
'https://github.com/ansible-collections/community.docker/issues/new?assignees=&labels=&projects=&template=bug_report.md'
|
||||||
|
.format(line)
|
||||||
|
)
|
||||||
|
match = _RE_RESOURCE_EVENT.match(line)
|
||||||
if match is not None:
|
if match is not None:
|
||||||
status = match.group('status')
|
status = match.group('status')
|
||||||
msg = None
|
msg = None
|
||||||
if status not in DOCKER_STATUS:
|
if status not in DOCKER_STATUS:
|
||||||
status, msg = msg, status
|
status, msg = msg, status
|
||||||
|
event = ResourceEvent(
|
||||||
|
ResourceType.from_docker_compose_event(match.group('resource_type')),
|
||||||
|
match.group('resource_id'),
|
||||||
|
status,
|
||||||
|
msg,
|
||||||
|
)
|
||||||
|
events.append(event)
|
||||||
|
if status in DOCKER_STATUS_ERROR:
|
||||||
|
error_event = event
|
||||||
|
else:
|
||||||
|
error_event = None
|
||||||
|
continue
|
||||||
|
match = _RE_PULL_EVENT.match(line)
|
||||||
|
if match:
|
||||||
events.append(
|
events.append(
|
||||||
ResourceEvent(
|
ResourceEvent(
|
||||||
ResourceType.from_docker_compose_event(match.group('resource_type')),
|
ResourceType.SERVICE,
|
||||||
match.group('resource_id'),
|
match.group('service'),
|
||||||
status,
|
match.group('status'),
|
||||||
msg,
|
None,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
error_event = None
|
||||||
# This could be a bug, a change of docker compose's output format, ...
|
continue
|
||||||
# Tell the user to report it to us :-)
|
match = _RE_ERROR_EVENT.match(line)
|
||||||
self.client.warn(
|
if match:
|
||||||
'Cannot parse event from line: {0!r}. Please report this at '
|
error_event = ResourceEvent(
|
||||||
'https://github.com/ansible-collections/community.docker/issues/new?assignees=&labels=&projects=&template=bug_report.md'
|
ResourceType.UNKNOWN,
|
||||||
.format(line)
|
match.group('resource_id'),
|
||||||
|
match.group('status'),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
|
events.append(error_event)
|
||||||
|
continue
|
||||||
|
if error_event is not None:
|
||||||
|
# Unparsable line that apparently belongs to the previous error event
|
||||||
|
error_event = ResourceEvent(
|
||||||
|
error_event.resource_type,
|
||||||
|
error_event.resource_id,
|
||||||
|
error_event.status,
|
||||||
|
'\n'.join(msg for msg in [error_event.msg, line] if msg is not None),
|
||||||
|
)
|
||||||
|
events[-1] = error_event
|
||||||
|
continue
|
||||||
|
if line.startswith('Error '):
|
||||||
|
# Error message that is independent of an error event
|
||||||
|
error_event = ResourceEvent(
|
||||||
|
ResourceType.UNKNOWN,
|
||||||
|
'',
|
||||||
|
'Error',
|
||||||
|
line,
|
||||||
|
)
|
||||||
|
events.append(error_event)
|
||||||
|
continue
|
||||||
|
# This could be a bug, a change of docker compose's output format, ...
|
||||||
|
# Tell the user to report it to us :-)
|
||||||
|
self.client.warn(
|
||||||
|
'Cannot parse event from line: {0!r}. Please report this at '
|
||||||
|
'https://github.com/ansible-collections/community.docker/issues/new?assignees=&labels=&projects=&template=bug_report.md'
|
||||||
|
.format(line)
|
||||||
|
)
|
||||||
return events
|
return events
|
||||||
|
|
||||||
def has_changes(self, events):
|
def has_changes(self, events):
|
||||||
@ -623,21 +726,44 @@ class ContainerManager(DockerBaseClass):
|
|||||||
msg=event.msg,
|
msg=event.msg,
|
||||||
))
|
))
|
||||||
|
|
||||||
def update_failed(self, result, events):
|
def is_failed(self, events, rc):
|
||||||
|
if rc:
|
||||||
|
return True
|
||||||
|
for event in events:
|
||||||
|
if event.status in DOCKER_STATUS_ERROR:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def update_failed(self, result, events, args, stdout, stderr, rc):
|
||||||
errors = []
|
errors = []
|
||||||
for event in events:
|
for event in events:
|
||||||
if event.status in DOCKER_STATUS_ERROR:
|
if event.status in DOCKER_STATUS_ERROR:
|
||||||
errors.append('Error when processing {resource_type} {resource_id}: {status}'.format(
|
msg = 'Error when processing {resource_type} {resource_id}: '
|
||||||
|
if event.resource_type == 'unknown':
|
||||||
|
msg = 'Error when processing {resource_id}: '
|
||||||
|
if event.resource_id == '':
|
||||||
|
msg = 'General error: '
|
||||||
|
msg += '{status}' if event.msg is None else '{msg}'
|
||||||
|
errors.append(msg.format(
|
||||||
resource_type=event.resource_type,
|
resource_type=event.resource_type,
|
||||||
resource_id=event.resource_id,
|
resource_id=event.resource_id,
|
||||||
status=event.status,
|
status=event.status,
|
||||||
|
msg=event.msg,
|
||||||
))
|
))
|
||||||
if errors:
|
if errors or rc:
|
||||||
|
if not errors:
|
||||||
|
errors.append('Return code {code} is non-zero'.format(code=rc))
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = '\n'.join(errors)
|
result['msg'] = '\n'.join(errors)
|
||||||
|
result['cmd'] = ' '.join(shlex_quote(arg) for arg in [self.client.get_cli()] + args)
|
||||||
|
result['stdout'] = to_native(stdout)
|
||||||
|
result['stderr'] = to_native(stderr)
|
||||||
|
result['rc'] = rc
|
||||||
|
|
||||||
def get_up_cmd(self, dry_run, no_start=False):
|
def get_up_cmd(self, dry_run, no_start=False):
|
||||||
args = self.get_base_args() + ['up', '--detach', '--no-color']
|
args = self.get_base_args() + ['up', '--detach', '--no-color', '--quiet-pull']
|
||||||
|
if self.pull != 'policy':
|
||||||
|
args.extend(['--pull', self.pull])
|
||||||
if self.remove_orphans:
|
if self.remove_orphans:
|
||||||
args.append('--remove-orphans')
|
args.append('--remove-orphans')
|
||||||
if self.recreate == 'always':
|
if self.recreate == 'always':
|
||||||
@ -658,12 +784,14 @@ class ContainerManager(DockerBaseClass):
|
|||||||
def cmd_up(self):
|
def cmd_up(self):
|
||||||
result = dict()
|
result = dict()
|
||||||
args = self.get_up_cmd(self.check_mode)
|
args = self.get_up_cmd(self.check_mode)
|
||||||
dummy, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src, check_rc=True)
|
rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src)
|
||||||
events = self.parse_events(stderr, dry_run=self.check_mode)
|
events = self.parse_events(stderr, dry_run=self.check_mode)
|
||||||
self.emit_warnings(events)
|
self.emit_warnings(events)
|
||||||
result['changed'] = self.has_changes(events)
|
result['changed'] = self.has_changes(events)
|
||||||
result['actions'] = self.extract_actions(events)
|
result['actions'] = self.extract_actions(events)
|
||||||
self.update_failed(result, events)
|
result['stdout'] = to_native(stdout)
|
||||||
|
result['stderr'] = to_native(stderr)
|
||||||
|
self.update_failed(result, events, args, stdout, stderr, rc)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_stop_cmd(self, dry_run):
|
def get_stop_cmd(self, dry_run):
|
||||||
@ -681,28 +809,44 @@ class ContainerManager(DockerBaseClass):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _combine_output(*outputs):
|
||||||
|
return b'\n'.join(out for out in outputs if out)
|
||||||
|
|
||||||
def cmd_stop(self):
|
def cmd_stop(self):
|
||||||
# Since 'docker compose stop' **always** claims its stopping containers, even if they are already
|
# Since 'docker compose stop' **always** claims its stopping containers, even if they are already
|
||||||
# stopped, we have to do this a bit more complicated.
|
# stopped, we have to do this a bit more complicated.
|
||||||
|
|
||||||
result = dict()
|
result = dict()
|
||||||
# Make sure all containers are created
|
# Make sure all containers are created
|
||||||
args = self.get_up_cmd(self.check_mode, no_start=True)
|
args_1 = self.get_up_cmd(self.check_mode, no_start=True)
|
||||||
dummy, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src, check_rc=True)
|
rc_1, stdout_1, stderr_1 = self.client.call_cli(*args_1, cwd=self.project_src)
|
||||||
events_1 = self.parse_events(stderr, dry_run=self.check_mode)
|
events_1 = self.parse_events(stderr_1, dry_run=self.check_mode)
|
||||||
self.emit_warnings(events_1)
|
self.emit_warnings(events_1)
|
||||||
if not self._are_containers_stopped():
|
is_failed_1 = self.is_failed(events_1, rc_1)
|
||||||
|
if not is_failed_1 and not self._are_containers_stopped():
|
||||||
# Make sure all containers are stopped
|
# Make sure all containers are stopped
|
||||||
args = self.get_stop_cmd(self.check_mode)
|
args_2 = self.get_stop_cmd(self.check_mode)
|
||||||
dummy, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src, check_rc=True)
|
rc_2, stdout_2, stderr_2 = self.client.call_cli(*args_2, cwd=self.project_src)
|
||||||
events_2 = self.parse_events(stderr, dry_run=self.check_mode)
|
events_2 = self.parse_events(stderr_2, dry_run=self.check_mode)
|
||||||
self.emit_warnings(events_2)
|
self.emit_warnings(events_2)
|
||||||
else:
|
else:
|
||||||
|
args_2 = []
|
||||||
|
rc_2, stdout_2, stderr_2 = 0, b'', b''
|
||||||
events_2 = []
|
events_2 = []
|
||||||
# Compose result
|
# Compose result
|
||||||
result['changed'] = self.has_changes(events_1) or self.has_changes(events_2)
|
result['changed'] = self.has_changes(events_1) or self.has_changes(events_2)
|
||||||
result['actions'] = self.extract_actions(events_1) + self.extract_actions(events_2)
|
result['actions'] = self.extract_actions(events_1) + self.extract_actions(events_2)
|
||||||
self.update_failed(result, events_1 + events_2)
|
result['stdout'] = to_native(self._combine_output(stdout_1, stdout_2))
|
||||||
|
result['stderr'] = to_native(self._combine_output(stderr_1, stderr_2))
|
||||||
|
self.update_failed(
|
||||||
|
result,
|
||||||
|
events_1 + events_2,
|
||||||
|
args_1 if is_failed_1 else args_2,
|
||||||
|
stdout_1 if is_failed_1 else stdout_2,
|
||||||
|
stderr_1 if is_failed_1 else stderr_2,
|
||||||
|
rc_1 if is_failed_1 else rc_2,
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_restart_cmd(self, dry_run):
|
def get_restart_cmd(self, dry_run):
|
||||||
@ -719,12 +863,14 @@ class ContainerManager(DockerBaseClass):
|
|||||||
def cmd_restart(self):
|
def cmd_restart(self):
|
||||||
result = dict()
|
result = dict()
|
||||||
args = self.get_restart_cmd(self.check_mode)
|
args = self.get_restart_cmd(self.check_mode)
|
||||||
dummy, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src, check_rc=True)
|
rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src)
|
||||||
events = self.parse_events(stderr, dry_run=self.check_mode)
|
events = self.parse_events(stderr, dry_run=self.check_mode)
|
||||||
self.emit_warnings(events)
|
self.emit_warnings(events)
|
||||||
result['changed'] = self.has_changes(events)
|
result['changed'] = self.has_changes(events)
|
||||||
result['actions'] = self.extract_actions(events)
|
result['actions'] = self.extract_actions(events)
|
||||||
self.update_failed(result, events)
|
result['stdout'] = to_native(stdout)
|
||||||
|
result['stderr'] = to_native(stderr)
|
||||||
|
self.update_failed(result, events, args, stdout, stderr, rc)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_down_cmd(self, dry_run):
|
def get_down_cmd(self, dry_run):
|
||||||
@ -745,12 +891,14 @@ class ContainerManager(DockerBaseClass):
|
|||||||
def cmd_down(self):
|
def cmd_down(self):
|
||||||
result = dict()
|
result = dict()
|
||||||
args = self.get_down_cmd(self.check_mode)
|
args = self.get_down_cmd(self.check_mode)
|
||||||
dummy, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src, check_rc=True)
|
rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src)
|
||||||
events = self.parse_events(stderr, dry_run=self.check_mode)
|
events = self.parse_events(stderr, dry_run=self.check_mode)
|
||||||
self.emit_warnings(events)
|
self.emit_warnings(events)
|
||||||
result['changed'] = self.has_changes(events)
|
result['changed'] = self.has_changes(events)
|
||||||
result['actions'] = self.extract_actions(events)
|
result['actions'] = self.extract_actions(events)
|
||||||
self.update_failed(result, events)
|
result['stdout'] = to_native(stdout)
|
||||||
|
result['stderr'] = to_native(stderr)
|
||||||
|
self.update_failed(result, events, args, stdout, stderr, rc)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -762,6 +910,7 @@ def main():
|
|||||||
profiles=dict(type='list', elements='str'),
|
profiles=dict(type='list', elements='str'),
|
||||||
state=dict(type='str', default='present', choices=['absent', 'present', 'stopped', 'restarted']),
|
state=dict(type='str', default='present', choices=['absent', 'present', 'stopped', 'restarted']),
|
||||||
dependencies=dict(type='bool', default=True),
|
dependencies=dict(type='bool', default=True),
|
||||||
|
pull=dict(type='str', choices=['always', 'missing', 'never', 'policy'], default='policy'),
|
||||||
recreate=dict(type='str', default='auto', choices=['always', 'never', 'auto']),
|
recreate=dict(type='str', default='auto', choices=['always', 'never', 'auto']),
|
||||||
remove_images=dict(type='str', choices=['all', 'local']),
|
remove_images=dict(type='str', choices=['all', 'local']),
|
||||||
remove_volumes=dict(type='bool', default=False),
|
remove_volumes=dict(type='bool', default=False),
|
||||||
|
|||||||
211
tests/integration/targets/docker_compose_v2/tasks/tests/pull.yml
Normal file
211
tests/integration/targets/docker_compose_v2/tasks/tests/pull.yml
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
- vars:
|
||||||
|
pname: "{{ name_prefix }}-pull"
|
||||||
|
cname: "{{ name_prefix }}-cont"
|
||||||
|
non_existing_image: does-not-exist:latest
|
||||||
|
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
|
||||||
|
test_service_non_existing: |
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
{{ cname }}:
|
||||||
|
image: {{ non_existing_image }}
|
||||||
|
test_service_alpine: |
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
{{ cname }}:
|
||||||
|
image: {{ docker_test_image_alpine }}
|
||||||
|
command: /bin/sh -c 'sleep 10m'
|
||||||
|
stop_grace_period: 1s
|
||||||
|
|
||||||
|
block:
|
||||||
|
- name: Registering container name
|
||||||
|
set_fact:
|
||||||
|
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
|
||||||
|
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
|
||||||
|
|
||||||
|
- name: Create project directory
|
||||||
|
file:
|
||||||
|
path: '{{ project_src }}'
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: Make sure images are not around
|
||||||
|
docker_image_remove:
|
||||||
|
name: '{{ item }}'
|
||||||
|
loop:
|
||||||
|
- '{{ non_existing_image }}'
|
||||||
|
- '{{ docker_test_image_alpine }}'
|
||||||
|
|
||||||
|
####################################################################
|
||||||
|
## Missing image ###################################################
|
||||||
|
####################################################################
|
||||||
|
|
||||||
|
- name: Template project file with non-existing image
|
||||||
|
copy:
|
||||||
|
dest: '{{ project_src }}/docker-compose.yml'
|
||||||
|
content: '{{ test_service_non_existing }}'
|
||||||
|
|
||||||
|
- name: Present with pull=never (check)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: never
|
||||||
|
check_mode: true
|
||||||
|
register: present_1_check
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Present with pull=never
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: never
|
||||||
|
register: present_1
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Present without explicit pull (check)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
check_mode: true
|
||||||
|
register: present_2_check
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Present without explicit pull
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
register: present_2
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- present_1_check is failed or present_1_check is changed
|
||||||
|
- present_1_check is changed or present_1_check.msg.startswith('General error:')
|
||||||
|
- present_1 is failed
|
||||||
|
- present_1.msg.startswith('General error:')
|
||||||
|
- present_2_check is failed
|
||||||
|
- present_2_check.msg.startswith('Error when processing ' ~ cname ~ ':')
|
||||||
|
- present_2 is failed
|
||||||
|
- present_2.msg.startswith('Error when processing ' ~ cname ~ ':')
|
||||||
|
|
||||||
|
####################################################################
|
||||||
|
## Regular image ###################################################
|
||||||
|
####################################################################
|
||||||
|
|
||||||
|
- name: Template project file with Alpine image
|
||||||
|
copy:
|
||||||
|
dest: '{{ project_src }}/docker-compose.yml'
|
||||||
|
content: '{{ test_service_alpine }}'
|
||||||
|
|
||||||
|
- name: Present with pull=missing (check)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
check_mode: true
|
||||||
|
register: present_1_check
|
||||||
|
|
||||||
|
- name: Present with pull=missing
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
register: present_1
|
||||||
|
|
||||||
|
- name: Present with pull=missing (idempotent, check)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
check_mode: true
|
||||||
|
register: present_2_check
|
||||||
|
|
||||||
|
- name: Present with pull=missing (idempotent)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
register: present_2
|
||||||
|
|
||||||
|
- name: Present with pull=always (check)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
check_mode: true
|
||||||
|
register: present_3_check
|
||||||
|
|
||||||
|
- name: Present with pull=always
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: present_3
|
||||||
|
|
||||||
|
- name: Stopping service
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Present with pull=never (check)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
check_mode: true
|
||||||
|
register: present_4_check
|
||||||
|
|
||||||
|
- name: Present with pull=never
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
register: present_4
|
||||||
|
|
||||||
|
- name: Present with pull=never (idempotent, check)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
check_mode: true
|
||||||
|
register: present_5_check
|
||||||
|
|
||||||
|
- name: Present with pull=never (idempotent)
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
register: present_5
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
docker_compose_v2:
|
||||||
|
project_src: '{{ project_src }}'
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- present_1_check is changed
|
||||||
|
- present_1_check.actions | selectattr('status', 'eq', 'Pulling') | first
|
||||||
|
- present_1_check.actions | selectattr('status', 'eq', 'Creating') | first
|
||||||
|
- present_1 is changed
|
||||||
|
- present_1.actions | selectattr('status', 'eq', 'Pulling') | first
|
||||||
|
- present_1.actions | selectattr('status', 'eq', 'Creating') | first
|
||||||
|
- present_2_check is not changed
|
||||||
|
- present_2 is not changed
|
||||||
|
- present_3_check is changed
|
||||||
|
- present_3_check.actions | selectattr('status', 'eq', 'Pulling') | first
|
||||||
|
- present_3_check.actions | selectattr('status', 'eq', 'Creating') | length == 0
|
||||||
|
- present_3_check.actions | selectattr('status', 'eq', 'Recreating') | length == 0
|
||||||
|
- present_3 is changed
|
||||||
|
- present_3.actions | selectattr('status', 'eq', 'Pulling') | first
|
||||||
|
- present_3.actions | selectattr('status', 'eq', 'Creating') | length == 0
|
||||||
|
- present_3.actions | selectattr('status', 'eq', 'Recreating') | length == 0
|
||||||
|
- present_4_check is changed
|
||||||
|
- present_4_check.actions | selectattr('status', 'eq', 'Pulling') | length == 0
|
||||||
|
- present_4 is changed
|
||||||
|
- present_4.actions | selectattr('status', 'eq', 'Pulling') | length == 0
|
||||||
|
- present_5_check is not changed
|
||||||
|
- present_5 is not changed
|
||||||
@ -3,18 +3,9 @@
|
|||||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
- name: Set up project and container names
|
- vars:
|
||||||
set_fact:
|
pname: "{{ name_prefix }}-start-stop"
|
||||||
pname: "{{ name_prefix }}"
|
cname: "{{ name_prefix }}-container"
|
||||||
cname: "{{ name_prefix ~ '-hi' }}"
|
|
||||||
|
|
||||||
- name: Registering container name
|
|
||||||
set_fact:
|
|
||||||
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
|
|
||||||
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
|
|
||||||
|
|
||||||
- name: Define services
|
|
||||||
set_fact:
|
|
||||||
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
|
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
|
||||||
test_service: |
|
test_service: |
|
||||||
version: '3'
|
version: '3'
|
||||||
@ -31,235 +22,241 @@
|
|||||||
command: '/bin/sh -c "sleep 15m"'
|
command: '/bin/sh -c "sleep 15m"'
|
||||||
stop_grace_period: 1s
|
stop_grace_period: 1s
|
||||||
|
|
||||||
- name: Create project directory
|
block:
|
||||||
file:
|
- name: Registering container name
|
||||||
path: '{{ project_src }}'
|
set_fact:
|
||||||
state: directory
|
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
|
||||||
|
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
|
||||||
|
|
||||||
|
- name: Create project directory
|
||||||
|
file:
|
||||||
|
path: '{{ project_src }}'
|
||||||
|
state: directory
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
## Present #########################################################
|
## Present #########################################################
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|
||||||
- name: Template default project file
|
- name: Template default project file
|
||||||
copy:
|
copy:
|
||||||
dest: '{{ project_src }}/docker-compose.yml'
|
dest: '{{ project_src }}/docker-compose.yml'
|
||||||
content: '{{ test_service }}'
|
content: '{{ test_service }}'
|
||||||
|
|
||||||
- name: Present (check)
|
- name: Present (check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_1_check
|
register: present_1_check
|
||||||
|
|
||||||
- name: Present
|
- name: Present
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
register: present_1
|
register: present_1
|
||||||
|
|
||||||
- name: Present (idempotent check)
|
- name: Present (idempotent check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_2_check
|
register: present_2_check
|
||||||
|
|
||||||
- name: Present (idempotent)
|
- name: Present (idempotent)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
register: present_2
|
register: present_2
|
||||||
|
|
||||||
- name: Template modified project file
|
- name: Template modified project file
|
||||||
copy:
|
copy:
|
||||||
dest: '{{ project_src }}/docker-compose.yml'
|
dest: '{{ project_src }}/docker-compose.yml'
|
||||||
content: '{{ test_service_mod }}'
|
content: '{{ test_service_mod }}'
|
||||||
|
|
||||||
- name: Present (changed check)
|
- name: Present (changed check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_3_check
|
register: present_3_check
|
||||||
|
|
||||||
- name: Present (changed)
|
- name: Present (changed)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
register: present_3
|
register: present_3
|
||||||
|
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- present_1_check is changed
|
- present_1_check is changed
|
||||||
- present_1 is changed
|
- present_1 is changed
|
||||||
- present_1.containers | length == 1
|
- present_1.containers | length == 1
|
||||||
- present_1.containers[0].Name == pname ~ '-' ~ cname ~ '-1'
|
- present_1.containers[0].Name == pname ~ '-' ~ cname ~ '-1'
|
||||||
- present_1.containers[0].Image == docker_test_image_alpine
|
- present_1.containers[0].Image == docker_test_image_alpine
|
||||||
- present_1.images | length == 1
|
- present_1.images | length == 1
|
||||||
- present_1.images[0].ContainerName == pname ~ '-' ~ cname ~ '-1'
|
- present_1.images[0].ContainerName == pname ~ '-' ~ cname ~ '-1'
|
||||||
- present_1.images[0].Repository == (docker_test_image_alpine | split(':') | first)
|
- present_1.images[0].Repository == (docker_test_image_alpine | split(':') | first)
|
||||||
- present_1.images[0].Tag == (docker_test_image_alpine | split(':') | last)
|
- present_1.images[0].Tag == (docker_test_image_alpine | split(':') | last)
|
||||||
- present_2_check is not changed
|
- present_2_check is not changed
|
||||||
- present_2 is not changed
|
- present_2 is not changed
|
||||||
- present_3_check is changed
|
- present_3_check is changed
|
||||||
- present_3 is changed
|
- present_3 is changed
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
## Absent ##########################################################
|
## Absent ##########################################################
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|
||||||
- name: Absent (check)
|
- name: Absent (check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: absent
|
state: absent
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: absent_1_check
|
register: absent_1_check
|
||||||
|
|
||||||
- name: Absent
|
- name: Absent
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: absent
|
state: absent
|
||||||
register: absent_1
|
register: absent_1
|
||||||
|
|
||||||
- name: Absent (idempotent check)
|
- name: Absent (idempotent check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: absent
|
state: absent
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: absent_2_check
|
register: absent_2_check
|
||||||
|
|
||||||
- name: Absent (idempotent)
|
- name: Absent (idempotent)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: absent
|
state: absent
|
||||||
register: absent_2
|
register: absent_2
|
||||||
|
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- absent_1_check is changed
|
- absent_1_check is changed
|
||||||
- absent_1 is changed
|
- absent_1 is changed
|
||||||
- absent_2_check is not changed
|
- absent_2_check is not changed
|
||||||
- absent_2 is not changed
|
- absent_2 is not changed
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
## Stopping and starting ###########################################
|
## Stopping and starting ###########################################
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|
||||||
- name: Template default project file
|
- name: Template default project file
|
||||||
copy:
|
copy:
|
||||||
dest: '{{ project_src }}/docker-compose.yml'
|
dest: '{{ project_src }}/docker-compose.yml'
|
||||||
content: '{{ test_service }}'
|
content: '{{ test_service }}'
|
||||||
|
|
||||||
- name: Present stopped (check)
|
- name: Present stopped (check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: stopped
|
state: stopped
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_1_check
|
register: present_1_check
|
||||||
|
|
||||||
- name: Present stopped
|
- name: Present stopped
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: stopped
|
state: stopped
|
||||||
register: present_1
|
register: present_1
|
||||||
|
|
||||||
- name: Present stopped (idempotent check)
|
- name: Present stopped (idempotent check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: stopped
|
state: stopped
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_2_check
|
register: present_2_check
|
||||||
|
|
||||||
- name: Present stopped (idempotent)
|
- name: Present stopped (idempotent)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: stopped
|
state: stopped
|
||||||
register: present_2
|
register: present_2
|
||||||
|
|
||||||
- name: Started (check)
|
- name: Started (check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_3_check
|
register: present_3_check
|
||||||
|
|
||||||
- name: Started
|
- name: Started
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
register: present_3
|
register: present_3
|
||||||
|
|
||||||
- name: Started (idempotent check)
|
- name: Started (idempotent check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_4_check
|
register: present_4_check
|
||||||
|
|
||||||
- name: Started (idempotent)
|
- name: Started (idempotent)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: present
|
state: present
|
||||||
register: present_4
|
register: present_4
|
||||||
|
|
||||||
- name: Restarted (check)
|
- name: Restarted (check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: restarted
|
state: restarted
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_5_check
|
register: present_5_check
|
||||||
|
|
||||||
- name: Restarted
|
- name: Restarted
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: restarted
|
state: restarted
|
||||||
register: present_5
|
register: present_5
|
||||||
|
|
||||||
- name: Stopped (check)
|
- name: Stopped (check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: stopped
|
state: stopped
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_6_check
|
register: present_6_check
|
||||||
|
|
||||||
- name: Stopped
|
- name: Stopped
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: stopped
|
state: stopped
|
||||||
register: present_6
|
register: present_6
|
||||||
|
|
||||||
- name: Restarted (check)
|
- name: Restarted (check)
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: restarted
|
state: restarted
|
||||||
check_mode: true
|
check_mode: true
|
||||||
register: present_7_check
|
register: present_7_check
|
||||||
|
|
||||||
- name: Restarted
|
- name: Restarted
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: restarted
|
state: restarted
|
||||||
register: present_7
|
register: present_7
|
||||||
|
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
docker_compose_v2:
|
docker_compose_v2:
|
||||||
project_src: '{{ project_src }}'
|
project_src: '{{ project_src }}'
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- present_1_check is changed
|
- present_1_check is changed
|
||||||
- present_1 is changed
|
- present_1 is changed
|
||||||
- present_2_check is not changed
|
- present_2_check is not changed
|
||||||
- present_2 is not changed
|
- present_2 is not changed
|
||||||
- present_3_check is changed
|
- present_3_check is changed
|
||||||
- present_3 is changed
|
- present_3 is changed
|
||||||
- present_4_check is not changed
|
- present_4_check is not changed
|
||||||
- present_4 is not changed
|
- present_4 is not changed
|
||||||
- present_5_check is changed
|
- present_5_check is changed
|
||||||
- present_5 is changed
|
- present_5 is changed
|
||||||
- present_6_check is changed
|
- present_6_check is changed
|
||||||
- present_6 is changed
|
- present_6 is changed
|
||||||
- present_7_check is changed
|
- present_7_check is changed
|
||||||
- present_7 is changed
|
- present_7 is changed
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user