From 107e956565347b97fb95345793de7128526a56f0 Mon Sep 17 00:00:00 2001 From: Jose Angel Munoz Date: Wed, 5 Aug 2020 08:16:32 +0200 Subject: [PATCH] New Docker Stack Task Info Module with Tests (#732) * Add docker_stack_task_info with tests * Change link * Change ln * Fix Documentation * Small doc changes * Remove node for RH --- .../cloud/docker/docker_stack_task_info.py | 95 +++++++++++++++++++ plugins/modules/docker_stack_task_info.py | 1 + .../targets/docker_stack_task_info/aliases | 8 ++ .../files/stack_compose_base.yml | 5 + .../files/stack_compose_overrides.yml | 5 + .../docker_stack_task_info/meta/main.yml | 3 + .../docker_stack_task_info/tasks/main.yml | 5 + .../tasks/test_stack_task_info.yml | 80 ++++++++++++++++ .../docker_stack_task_info/vars/main.yml | 15 +++ 9 files changed, 217 insertions(+) create mode 100644 plugins/modules/cloud/docker/docker_stack_task_info.py create mode 120000 plugins/modules/docker_stack_task_info.py create mode 100644 tests/integration/targets/docker_stack_task_info/aliases create mode 100644 tests/integration/targets/docker_stack_task_info/files/stack_compose_base.yml create mode 100644 tests/integration/targets/docker_stack_task_info/files/stack_compose_overrides.yml create mode 100644 tests/integration/targets/docker_stack_task_info/meta/main.yml create mode 100644 tests/integration/targets/docker_stack_task_info/tasks/main.yml create mode 100644 tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml create mode 100644 tests/integration/targets/docker_stack_task_info/vars/main.yml diff --git a/plugins/modules/cloud/docker/docker_stack_task_info.py b/plugins/modules/cloud/docker/docker_stack_task_info.py new file mode 100644 index 0000000000..966a42660c --- /dev/null +++ b/plugins/modules/cloud/docker/docker_stack_task_info.py @@ -0,0 +1,95 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Jose Angel Munoz (@imjoseangel) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: docker_stack_task_info +author: "Jose Angel Munoz (@imjoseangel)" +short_description: Return information of the tasks on a docker stack +description: + - Retrieve information on docker stacks tasks using the C(docker stack) command + on the target node (see examples). +options: + name: + description: + - Stack name. + type: str + required: yes +version_added: "1.1.0" +''' + +RETURN = ''' +results: + description: | + List of dictionaries containing the list of tasks associated + to a stack name. + sample: > + [{"CurrentState":"Running","DesiredState":"Running","Error":"","ID":"7wqv6m02ugkw","Image":"busybox","Name":"test_stack.1","Node":"swarm","Ports":""}] + returned: always + type: list + elements: dict +''' + +EXAMPLES = ''' + - name: Shows stack info + community.general.docker_stack_task_info: + name: test_stack + register: result + + - name: Show results + ansible.builtin.debug: + var: result.results +''' + +import json +from ansible.module_utils.basic import AnsibleModule + + +def docker_stack_task(module, stack_name): + docker_bin = module.get_bin_path('docker', required=True) + rc, out, err = module.run_command( + [docker_bin, "stack", "ps", stack_name, "--format={{json .}}"]) + + return rc, out.strip(), err.strip() + + +def main(): + module = AnsibleModule( + argument_spec={ + 'name': dict(type='str', required=True) + }, + supports_check_mode=False + ) + + name = module.params['name'] + + rc, out, err = docker_stack_task(module, name) + + if rc != 0: + module.fail_json(msg="Error running docker stack. {0}".format(err), + rc=rc, stdout=out, stderr=err) + else: + if out: + ret = list( + json.loads(outitem) + for outitem in out.splitlines()) + + else: + ret = [] + + module.exit_json(changed=False, + rc=rc, + stdout=out, + stderr=err, + results=ret) + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/docker_stack_task_info.py b/plugins/modules/docker_stack_task_info.py new file mode 120000 index 0000000000..c0a462bf08 --- /dev/null +++ b/plugins/modules/docker_stack_task_info.py @@ -0,0 +1 @@ +./cloud/docker/docker_stack_task_info.py \ No newline at end of file diff --git a/tests/integration/targets/docker_stack_task_info/aliases b/tests/integration/targets/docker_stack_task_info/aliases new file mode 100644 index 0000000000..620dd25f5e --- /dev/null +++ b/tests/integration/targets/docker_stack_task_info/aliases @@ -0,0 +1,8 @@ +shippable/posix/group1 +skip/aix +skip/osx +skip/freebsd +destructive +skip/docker # The tests sometimes make docker daemon unstable; hence, + # we skip all docker-based CI runs to avoid disrupting + # the whole CI system. diff --git a/tests/integration/targets/docker_stack_task_info/files/stack_compose_base.yml b/tests/integration/targets/docker_stack_task_info/files/stack_compose_base.yml new file mode 100644 index 0000000000..4a3e7963b4 --- /dev/null +++ b/tests/integration/targets/docker_stack_task_info/files/stack_compose_base.yml @@ -0,0 +1,5 @@ +version: '3' +services: + busybox: + image: busybox:latest + command: sleep 3600 diff --git a/tests/integration/targets/docker_stack_task_info/files/stack_compose_overrides.yml b/tests/integration/targets/docker_stack_task_info/files/stack_compose_overrides.yml new file mode 100644 index 0000000000..1b81c71b30 --- /dev/null +++ b/tests/integration/targets/docker_stack_task_info/files/stack_compose_overrides.yml @@ -0,0 +1,5 @@ +version: '3' +services: + busybox: + environment: + envvar: value diff --git a/tests/integration/targets/docker_stack_task_info/meta/main.yml b/tests/integration/targets/docker_stack_task_info/meta/main.yml new file mode 100644 index 0000000000..07da8c6dda --- /dev/null +++ b/tests/integration/targets/docker_stack_task_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_docker diff --git a/tests/integration/targets/docker_stack_task_info/tasks/main.yml b/tests/integration/targets/docker_stack_task_info/tasks/main.yml new file mode 100644 index 0000000000..7995d2a298 --- /dev/null +++ b/tests/integration/targets/docker_stack_task_info/tasks/main.yml @@ -0,0 +1,5 @@ +- include_tasks: test_stack_task_info.yml + when: docker_api_version is version('1.25', '>=') + +- fail: msg="Too old docker / docker-py version to run docker_stack tests!" + when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6) diff --git a/tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml b/tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml new file mode 100644 index 0000000000..024f498660 --- /dev/null +++ b/tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml @@ -0,0 +1,80 @@ +--- +- block: + - name: Make sure we're not already using Docker swarm + docker_swarm: + state: absent + force: true + + - name: Get docker_stack_info when docker is not running in swarm mode + docker_stack_info: + ignore_errors: true + register: output + + - name: Assert failure when called when swarm is not running + assert: + that: + - 'output is failed' + - '"Error running docker stack" in output.msg' + + - name: Create a swarm cluster + docker_swarm: + state: present + advertise_addr: "{{ ansible_default_ipv4.address }}" + + - name: Get docker_stack_info when docker is running and not stack available + docker_stack_info: + register: output + + - name: Assert stack facts + assert: + that: + - 'output.results | type_debug == "list"' + - 'output.results | length == 0' + + - name: Copy compose files + copy: + src: "{{ item }}" + dest: "{{ output_dir }}/" + with_items: + - stack_compose_base.yml + - stack_compose_overrides.yml + + - name: Install docker_stack python requirements + pip: + name: jsondiff,pyyaml + + - name: Create stack with compose file + register: output + docker_stack: + state: present + name: test_stack + compose: + - "{{ output_dir }}/stack_compose_base.yml" + + - name: Assert test_stack changed on stack creation with compose file + assert: + that: + - output is changed + + - name: Get docker_stack_info when docker is running + docker_stack_info: + register: output + + - name: Get docker_stack_task_info first element + docker_stack_task_info: + name: "{{ output.results[0].Name }}" + register: output + + - name: assert stack facts + assert: + that: + - 'output.results | type_debug == "list"' + - 'output.results[0].DesiredState == "Running"' + - 'output.results[0].Image == "busybox:latest"' + - 'output.results[0].Name == "test_stack_busybox.1"' + + always: + - name: Cleanup + docker_swarm: + state: absent + force: true diff --git a/tests/integration/targets/docker_stack_task_info/vars/main.yml b/tests/integration/targets/docker_stack_task_info/vars/main.yml new file mode 100644 index 0000000000..0872f23784 --- /dev/null +++ b/tests/integration/targets/docker_stack_task_info/vars/main.yml @@ -0,0 +1,15 @@ +stack_compose_base: + version: '3' + services: + busybox: + image: busybox:latest + command: sleep 3600 + +stack_compose_overrides: + version: '3' + services: + busybox: + environment: + envvar: value + +stack_update_expected_diff: '{"test_stack_busybox": {"TaskTemplate": {"ContainerSpec": {"Env": ["envvar=value"]}}}}'