docker_swarm_service_info: Read information about swarm services (#55008)

* Add docker_swarm_service_info module

* Remove unused import

* Limit to retrieving info about one service

* Add exists return value

* Add yaml 3-dash

Co-Authored-By: hannseman <hannes@5monkeys.se>

* Document return value as jinja `none´

Co-Authored-By: hannseman <hannes@5monkeys.se>

* Name is required
This commit is contained in:
Hannes Ljungberg 2019-04-11 12:30:00 +02:00 committed by Martin Krizek
parent 21ec3b294f
commit 23d0d225f4
6 changed files with 222 additions and 1 deletions

View file

@ -4,7 +4,6 @@
import json
from time import sleep
from re import split
try:
from docker.errors import APIError
@ -249,3 +248,29 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient):
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

View file

@ -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()

View file

@ -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.

View file

@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View file

@ -0,0 +1,6 @@
---
- include_tasks: test_docker_swarm_service_info.yml
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)

View file

@ -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