From bc5dde0e2512c0caac8361a24db47bd7935af95d Mon Sep 17 00:00:00 2001 From: Jose Angel Munoz Date: Wed, 29 Jul 2020 14:56:49 +0200 Subject: [PATCH] New docker_stack_module with tests (#576) * First docker stack info approach without tests Fixes results when no stack availabl Fixes sanity test Fixing links Fixes tabs Fixes long line Improving Json Output Changes arguments Lint with autopep8 Moves imports Adds extra line Adds Tests Adds pip and fixes return empty Fixes silly missing else * Adds Tests and Fixes comments * Removes tasks option * Removes arguments * Changes error message * Changes Tests * Add proposals f * Improve output * Change test for output change * Add debug --- .../modules/cloud/docker/docker_stack_info.py | 84 +++++++++++++++++++ plugins/modules/docker_stack_info.py | 1 + .../targets/docker_stack_info/aliases | 8 ++ .../files/stack_compose_base.yml | 5 ++ .../files/stack_compose_overrides.yml | 5 ++ .../targets/docker_stack_info/meta/main.yml | 3 + .../targets/docker_stack_info/tasks/main.yml | 5 ++ .../tasks/test_stack_info.yml | 75 +++++++++++++++++ .../targets/docker_stack_info/vars/main.yml | 15 ++++ 9 files changed, 201 insertions(+) create mode 100644 plugins/modules/cloud/docker/docker_stack_info.py create mode 120000 plugins/modules/docker_stack_info.py create mode 100644 tests/integration/targets/docker_stack_info/aliases create mode 100644 tests/integration/targets/docker_stack_info/files/stack_compose_base.yml create mode 100644 tests/integration/targets/docker_stack_info/files/stack_compose_overrides.yml create mode 100644 tests/integration/targets/docker_stack_info/meta/main.yml create mode 100644 tests/integration/targets/docker_stack_info/tasks/main.yml create mode 100644 tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml create mode 100644 tests/integration/targets/docker_stack_info/vars/main.yml diff --git a/plugins/modules/cloud/docker/docker_stack_info.py b/plugins/modules/cloud/docker/docker_stack_info.py new file mode 100644 index 0000000000..74a3648df2 --- /dev/null +++ b/plugins/modules/cloud/docker/docker_stack_info.py @@ -0,0 +1,84 @@ +#!/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_info +author: "Jose Angel Munoz (@imjoseangel)" +short_description: Return information on a docker stack +description: + - Retrieve information on docker stacks using the C(docker stack) command + on the target node (see examples). +version_added: "1.0.0" +''' + +RETURN = ''' +results: + description: | + List of dictionaries containing the list of stacks or tasks associated + to a stack name. + sample: > + "results": [{"name":"grafana","namespace":"default","orchestrator":"Kubernetes","services":"2"}] + returned: always + type: list +''' + +EXAMPLES = ''' + - name: Shows stack info + community.general.docker_stack_info: + register: result + + - name: Show results + ansible.builtin.debug: + var: result.results +''' + +import json +from ansible.module_utils.basic import AnsibleModule + + +def docker_stack_list(module): + docker_bin = module.get_bin_path('docker', required=True) + rc, out, err = module.run_command( + [docker_bin, "stack", "ls", "--format={{json .}}"]) + + return rc, out.strip(), err.strip() + + +def main(): + module = AnsibleModule( + argument_spec={ + }, + supports_check_mode=False + ) + + rc, out, err = docker_stack_list(module) + + 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_info.py b/plugins/modules/docker_stack_info.py new file mode 120000 index 0000000000..c1bbd31f8e --- /dev/null +++ b/plugins/modules/docker_stack_info.py @@ -0,0 +1 @@ +./cloud/docker/docker_stack_info.py \ No newline at end of file diff --git a/tests/integration/targets/docker_stack_info/aliases b/tests/integration/targets/docker_stack_info/aliases new file mode 100644 index 0000000000..620dd25f5e --- /dev/null +++ b/tests/integration/targets/docker_stack_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_info/files/stack_compose_base.yml b/tests/integration/targets/docker_stack_info/files/stack_compose_base.yml new file mode 100644 index 0000000000..4a3e7963b4 --- /dev/null +++ b/tests/integration/targets/docker_stack_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_info/files/stack_compose_overrides.yml b/tests/integration/targets/docker_stack_info/files/stack_compose_overrides.yml new file mode 100644 index 0000000000..1b81c71b30 --- /dev/null +++ b/tests/integration/targets/docker_stack_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_info/meta/main.yml b/tests/integration/targets/docker_stack_info/meta/main.yml new file mode 100644 index 0000000000..07da8c6dda --- /dev/null +++ b/tests/integration/targets/docker_stack_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_docker diff --git a/tests/integration/targets/docker_stack_info/tasks/main.yml b/tests/integration/targets/docker_stack_info/tasks/main.yml new file mode 100644 index 0000000000..3ae1ff5be4 --- /dev/null +++ b/tests/integration/targets/docker_stack_info/tasks/main.yml @@ -0,0 +1,5 @@ +- include_tasks: test_stack_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_info/tasks/test_stack_info.yml b/tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml new file mode 100644 index 0000000000..1754312a27 --- /dev/null +++ b/tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml @@ -0,0 +1,75 @@ +--- +- 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: assert stack facts + assert: + that: + - 'output.results | type_debug == "list"' + - 'output.results[0].Name == "test_stack"' + - 'output.results[0].Orchestrator == "Swarm"' + - 'output.results[0].Services == "1"' + + always: + - name: Cleanup + docker_swarm: + state: absent + force: true diff --git a/tests/integration/targets/docker_stack_info/vars/main.yml b/tests/integration/targets/docker_stack_info/vars/main.yml new file mode 100644 index 0000000000..0872f23784 --- /dev/null +++ b/tests/integration/targets/docker_stack_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"]}}}}'