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_swarm_service_info: Read information about swarm services #55008

Merged
merged 7 commits into from
Apr 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 26 additions & 1 deletion lib/ansible/module_utils/docker/swarm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import json
from time import sleep
from re import split

try:
from docker.errors import APIError
Expand Down Expand Up @@ -249,3 +248,29 @@ def get_unlock_key(self):
if self.docker_py_version < LooseVersion('2.7.0'):
return None
return super(AnsibleDockerSwarmClient, self).get_unlock_key()

def get_service_inspect(self, service_id, skip_missing=False):
"""
Returns Swarm service info as in 'docker service inspect' command about single service

:param service_id: service ID or name
:param skip_missing: if True then function will return None instead of failing the task
:return:
Single service information structure
"""
try:
service_info = self.inspect_service(service=service_id)
except APIError as exc:
if exc.status_code == 503:
self.fail("Cannot inspect service: To inspect service execute module on Swarm Manager")
if exc.status_code == 404:
if skip_missing is False:
self.fail("Error while reading from Swarm manager: %s" % to_native(exc))
else:
return None
except Exception as exc:
self.fail("Error inspecting swarm service: %s" % exc)

json_str = json.dumps(service_info, ensure_ascii=False)
service_info = json.loads(json_str)
return service_info
104 changes: 104 additions & 0 deletions lib/ansible/modules/cloud/docker/docker_swarm_service_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/python
#
# (c) 2019 Hannes Ljungberg <hannes.ljungberg@gmail.com>
# 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


ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}

DOCUMENTATION = '''
---
module: docker_swarm_service_info

short_description: Retrieves information about docker services from a Swarm Manager

description:
- Retrieves information about a docker service.
- Essentially returns the output of C(docker service inspect <name>).
- Must be executed on a host running as Swarm Manager, otherwise the module will fail.

version_added: "2.8"

options:
name:
description:
- The name of the service to inspect.
type: str
required: yes
extends_documentation_fragment:
- docker
- docker.docker_py_1_documentation

author:
- Hannes Ljungberg (@hannseman)

requirements:
- "L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 2.0.0"
- "Docker API >= 1.24"
'''

EXAMPLES = '''
- name: Get info from a service
docker_swarm_service_info:
name: myservice
register: result
'''

RETURN = '''
exists:
description:
- Returns whether the service exists.
type: bool
returned: always
sample: true
service:
description:
- A dictionary representing the current state of the service. Matches the C(docker service inspect) output.
- Will be C(none) if service does not exist.
returned: always
type: dict
'''

from ansible.module_utils.docker.swarm import AnsibleDockerSwarmClient


def get_service_info(client):
service = client.module.params['name']
return client.get_service_inspect(
service_id=service,
skip_missing=True
)


def main():
argument_spec = dict(
name=dict(type='str', required=True),
)

client = AnsibleDockerSwarmClient(
argument_spec=argument_spec,
supports_check_mode=True,
min_docker_version='2.0.0',
min_docker_api_version='1.24',
)

client.fail_task_if_not_swarm_manager()

service = get_service_info(client)

client.module.exit_json(
changed=False,
service=service,
exists=bool(service)
)


if __name__ == '__main__':
main()
7 changes: 7 additions & 0 deletions test/integration/targets/docker_swarm_service_info/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
shippable/posix/group3
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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- include_tasks: test_docker_swarm_service_info.yml
hannseman marked this conversation as resolved.
Show resolved Hide resolved
when: docker_py_version is version('2.0.0', '>=') and docker_api_version is version('1.24', '>=')

- fail: msg="Too old docker / docker-py version to run docker_swarm_service_info tests!"
when: not(docker_py_version is version('2.0.0', '>=') and docker_api_version is version('1.24', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---

- name: Generate service base name
set_fact:
service_base_name: "{{ 'ansible-test-%0x' % ((2**32) | random) }}"

- name: Registering service names
set_fact:
service_name: "{{ service_base_name ~ '-1' }}"

- block:
- name: Make sure we're not already using Docker swarm
docker_swarm:
state: absent
force: true

- name: Try to get docker_swarm_service_info when docker is not running in swarm mode
docker_swarm_service_info:
name: "{{ service_name }}"
ignore_errors: yes
register: output

- name: assert failure when called when swarm is not in use or not run on manager node
assert:
that:
- 'output is failed'
- 'output.msg == "Error running docker swarm module: must run on swarm manager node"'

- name: Create a Swarm cluster
docker_swarm:
state: present
register: output

- name: Create services
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8

- name: Try to get docker_swarm_service_info for a single service
docker_swarm_service_info:
name: "{{ service_name }}"
register: output

- name: assert reading reading service info
assert:
that:
- 'output.exists == true'
- 'output.service.ID is string'
- 'output.service.Spec.Name == service_name'

- name: Create random name
set_fact:
random_service_name: "{{ 'random-service-%0x' % ((2**32) | random) }}"

- name: Try to get docker_swarm_service_info using random service name as parameter
docker_swarm_service_info:
name: "{{ random_service_name }}"
register: output

- name: assert reading reading service info
assert:
that:
- 'output.service is none'
- 'output.exists == false'

always:
- name: Remove services
docker_swarm_service:
name: "{{ service_name }}"
state: absent
ignore_errors: yes

- name: Remove swarm
docker_swarm:
state: absent
force: true