Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docker-compose - Adding validated state and no_interpolate option #169

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions 162-docker_container_publish_all_option.yml

This file was deleted.

4 changes: 4 additions & 0 deletions changelogs/fragments/169-docker_compose-validate-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
minor_changes:
- docker_compose - added ``no-interpolate`` option and new state ``validated`` to provide behavior similar to
``docker-compose config`` (https://github.com/ansible-collections/community.docker/pull/169).
38 changes: 34 additions & 4 deletions plugins/modules/docker_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,14 @@
- Specifying C(present) is the same as running C(docker-compose up) resp. C(docker-compose stop) (with I(stopped)) resp. C(docker-compose restart)
(with I(restarted)).
- Specifying C(absent) is the same as running C(docker-compose down).
- Specifying C(validated) is the same as running C(docker-compose config) which validates the provided compose
files and returns the contained configuration.
type: str
default: present
choices:
- absent
- present
- validated
services:
description:
- When I(state) is C(present) run C(docker-compose up) resp. C(docker-compose stop) (with I(stopped)) resp. C(docker-compose restart) (with I(restarted))
Expand Down Expand Up @@ -154,6 +157,12 @@
- Timeout in seconds for container shutdown when attached or when containers are already running.
type: int
default: 10
no_interpolate:
description:
- Do not interpolate environment variables in configuration when I(state=validated).
- Requires C(docker-compose) version 1.25.0 or greater.
type: bool
version_added: 1.9.0
use_ssh_client:
description:
- Currently ignored for this module, but might suddenly be supported later on.
Expand Down Expand Up @@ -455,6 +464,12 @@
description: the container's short ID
returned: always
type: str
config:
description:
- The resulting configuration from one or more compose files.
- Equivalent to the output of C(docker-compose config).
returned: when success and I(state=validated)
type: dict
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type: dict
type: dict
version_added: 1.9.0

'''

import os
Expand All @@ -481,10 +496,11 @@

try:
from compose import __version__ as compose_version
from compose.cli.command import project_from_options
from compose.cli.command import project_from_options, get_config_from_options
from compose.service import NoSuchImageError
from compose.cli.main import convergence_strategy_from_opts, build_action_from_opts, image_type_from_opt
from compose.const import DEFAULT_TIMEOUT, LABEL_SERVICE, LABEL_PROJECT, LABEL_ONE_OFF
from compose.config.serialize import serialize_config
HAS_COMPOSE = True
HAS_COMPOSE_EXC = None
MINIMUM_COMPOSE_VERSION = '1.7.0'
Expand Down Expand Up @@ -691,8 +707,10 @@ def exec_module(self):
result = self.cmd_up()
elif self.state == 'absent':
result = self.cmd_down()
elif self.state == 'validated':
return self.validate_config()

if self.definition:
if self.definition and not self.state == 'validated':
compose_file = os.path.join(self.project_src, "docker-compose.yml")
self.log("removing %s" % compose_file)
os.remove(compose_file)
Expand Down Expand Up @@ -1112,6 +1130,17 @@ def cmd_scale(self):
result['actions'].append(service_res)
return result

def validate_config(self):
if LooseVersion(compose_version) >= LooseVersion('1.25.0'):
config = get_config_from_options(self.project_src, self.options, {'--no-interpolate': self.no_interpolate})
else:
config = get_config_from_options(self.project_src, self.options)

return {
'changed': False,
'config': yaml.load(serialize_config(config))
}

def parse_scale(self, service_name):
try:
return int(self.scale[service_name])
Expand All @@ -1126,7 +1155,7 @@ def main():
project_name=dict(type='str',),
files=dict(type='list', elements='path'),
profiles=dict(type='list', elements='str'),
state=dict(type='str', default='present', choices=['absent', 'present']),
state=dict(type='str', default='present', choices=['absent', 'present', 'validated']),
definition=dict(type='dict'),
hostname_check=dict(type='bool', default=False),
recreate=dict(type='str', default='smart', choices=['always', 'never', 'smart']),
Expand All @@ -1142,7 +1171,8 @@ def main():
pull=dict(type='bool', default=False),
nocache=dict(type='bool', default=False),
debug=dict(type='bool', default=False),
timeout=dict(type='int', default=DEFAULT_TIMEOUT)
timeout=dict(type='int', default=DEFAULT_TIMEOUT),
no_interpolate=dict(type='bool')
)

mutually_exclusive = [
Expand Down
50 changes: 49 additions & 1 deletion tests/integration/targets/docker_compose/tasks/tests/options.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,52 @@
vars:
cname_1_name: "{{ pname + '_' + cname_1 + '_1' }}"
cname_2_name: "{{ pname + '_' + cname_2 + '_1' }}"
when: docker_compose_version is version('1.28.0', '>=')
when: docker_compose_version is version('1.28.0', '>=')

####################################################################
## no_interpolate ##################################################
####################################################################

- block:
- name: Define service
set_fact:
sleep_time: 10m
test_service: |
version: '2'
services:
{{ cname_1 }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep ${SLEEP_TIME}"'
stop_grace_period: 1s
test_cases:
- test_name: unspecified
- test_name: "false"
no_interpolate_value: false
- test_name: "true"
no_interpolate_value: true

- name: no_interpolate tests
environment:
SLEEP_TIME: "{{ sleep_time }}"
docker_compose:
project_name: "{{ pname }}"
definition: "{{ test_service | from_yaml }}"
state: validated
no_interpolate: "{{ test_case.no_interpolate_value | default(omit) }}"
register: no_interpolate_outputs
loop_control:
loop_var: test_case
loop: "{{ test_cases }}"

- name: Cleanup
docker_compose:
project_name: "{{ pname }}"
state: absent
definition: "{{ test_service | from_yaml }}"

- assert:
that:
- sleep_time in no_interpolate_outputs.results[0].config.services[cname_1].command
- sleep_time in no_interpolate_outputs.results[1].config.services[cname_1].command
- "'${SLEEP_TIME}' in no_interpolate_outputs.results[2].config.services[cname_1].command"
when: docker_compose_version is version('1.25.0', '>=')
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 15m"'
stop_grace_period: 1s
broken_service: |
version: '2'
services:
broken:
image
command:
stop_grace_period: 1s

####################################################################
## Present #########################################################
Expand Down Expand Up @@ -227,3 +234,28 @@
- started_4 is not changed
- stopped_1 is changed
- stopped_2 is changed

####################################################################
## Validated ######################################################
####################################################################

- name: Validated success
docker_compose:
project_name: "{{ pname }}"
state: validated
definition: "{{ test_service | from_yaml }}"
register: validated_success

- name: Validated failure
docker_compose:
project_name: "{{ pname }}"
state: validated
definition: "{{ broken_service | from_yaml }}"
ignore_errors: true
register: validated_failure

- assert:
that:
- validated_success is success
- validated_success.config != {}
- validated_failure is failed