diff --git a/lib/ansible/module_utils/docker_common.py b/lib/ansible/module_utils/docker_common.py index b7b770fcca1..d54dd9621d1 100644 --- a/lib/ansible/module_utils/docker_common.py +++ b/lib/ansible/module_utils/docker_common.py @@ -457,6 +457,45 @@ class AnsibleDockerClient(Client): return result + def get_network(self, name=None, id=None): + ''' + Lookup a network and return the inspection results. + ''' + if name is None and id is None: + return None + + result = None + + if id is None: + try: + for network in self.networks(): + self.log("testing network: %s" % (network['Name'])) + if name == network['Name']: + result = network + break + if network['Id'].startswith(name): + result = network + break + except SSLError as exc: + self._handle_ssl_error(exc) + except Exception as exc: + self.fail("Error retrieving network list: %s" % exc) + + if result is not None: + id = result['Id'] + + if id is not None: + try: + self.log("Inspecting network Id %s" % id) + result = self.inspect_network(id) + self.log("Completed network inspection") + except NotFound as exc: + return None + except Exception as exc: + self.fail("Error inspecting network: %s" % exc) + + return result + def find_image(self, name, tag): ''' Lookup an image (by name and tag) and return the inspection results. diff --git a/lib/ansible/modules/cloud/docker/docker_network.py b/lib/ansible/modules/cloud/docker/docker_network.py index 804b502ea99..2c1bff5ba93 100644 --- a/lib/ansible/modules/cloud/docker/docker_network.py +++ b/lib/ansible/modules/cloud/docker/docker_network.py @@ -424,10 +424,7 @@ class DockerNetworkManager(object): self.results['diff'] = self.diff_result def get_existing_network(self): - try: - return self.client.inspect_network(self.parameters.network_name) - except NotFound: - return None + return self.client.get_network(name=self.parameters.network_name) def has_different_config(self, net): ''' @@ -552,7 +549,7 @@ class DockerNetworkManager(object): if not self.check_mode: resp = self.client.create_network(self.parameters.network_name, **params) - self.existing_network = self.client.inspect_network(resp['Id']) + self.existing_network = self.client.get_network(id=resp['Id']) self.results['actions'].append("Created network %s with driver %s" % (self.parameters.network_name, self.parameters.driver)) self.results['changed'] = True @@ -590,7 +587,7 @@ class DockerNetworkManager(object): self.disconnect_container(name) def disconnect_all_containers(self): - containers = self.client.inspect_network(self.parameters.network_name)['Containers'] + containers = self.client.get_network(name=self.parameters.network_name)['Containers'] if not containers: return for cont in containers.values(): diff --git a/lib/ansible/modules/cloud/docker/docker_network_facts.py b/lib/ansible/modules/cloud/docker/docker_network_facts.py new file mode 100644 index 00000000000..2cfadbe0ae2 --- /dev/null +++ b/lib/ansible/modules/cloud/docker/docker_network_facts.py @@ -0,0 +1,137 @@ +#!/usr/bin/python +# +# Copyright 2016 Red Hat | Ansible +# 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_network_facts + +short_description: Retrieves facts about docker network + +description: + - Retrieves facts about a docker network. + - Essentially returns the output of C(docker network inspect ), similar to what M(docker_network) + returns for a non-absent network. + +version_added: "2.8" + +options: + name: + description: + - The name of the network to inspect. + - When identifying an existing network name may be a name or a long or short network ID. + required: true +extends_documentation_fragment: + - docker + +author: + - "Dave Bendit (@DBendit)" + +requirements: + - "python >= 2.6" + - "docker-py >= 1.8.0" + - "Please note that the L(docker-py,https://pypi.org/project/docker-py/) Python + module has been superseded by L(docker,https://pypi.org/project/docker/) + (see L(here,https://github.com/docker/docker-py/issues/1310) for details). + For Python 2.6, C(docker-py) must be used. Otherwise, it is recommended to + install the C(docker) Python module. Note that both modules should I(not) + be installed at the same time. Also note that when both modules are installed + and one of them is uninstalled, the other might no longer function and a + reinstall of it is required." + - "Docker API >= 1.21" +''' + +EXAMPLES = ''' +- name: Get infos on network + docker_network_facts: + name: mydata + register: result + +- name: Does network exist? + debug: + msg: "The network {{ 'exists' if result.exists else 'does not exist' }}" + +- name: Print information about network + debug: + var: result.docker_network + when: result.exists +''' + +RETURN = ''' +exists: + description: + - Returns whether the network exists. + type: bool + returned: always + sample: true +docker_network: + description: + - Facts representing the current state of the network. Matches the docker inspection output. + - Will be C(None) if network does not exist. + returned: always + type: dict + sample: '{ + "Attachable": false, + "ConfigFrom": { + "Network": "" + }, + "ConfigOnly": false, + "Containers": {}, + "Created": "2018-12-07T01:47:51.250835114-06:00", + "Driver": "bridge", + "EnableIPv6": false, + "IPAM": { + "Config": [ + { + "Gateway": "192.168.96.1", + "Subnet": "192.168.96.0/20" + } + ], + "Driver": "default", + "Options": null + }, + "Id": "0856968545f22026c41c2c7c3d448319d3b4a6a03a40b148b3ac4031696d1c0a", + "Ingress": false, + "Internal": false, + "Labels": {}, + "Name": "ansible-test-f2700bba", + "Options": {}, + "Scope": "local" + }' +''' + +from ansible.module_utils.docker_common import AnsibleDockerClient + + +def main(): + argument_spec = dict( + name=dict(type='str', required=True), + ) + + client = AnsibleDockerClient( + argument_spec=argument_spec, + supports_check_mode=True, + min_docker_api_version='1.21', + ) + + network = client.get_network(client.module.params['name']) + + client.module.exit_json( + changed=False, + exists=(True if network else False), + docker_network=network, + ) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/docker_network_facts/aliases b/test/integration/targets/docker_network_facts/aliases new file mode 100644 index 00000000000..80f0500dfff --- /dev/null +++ b/test/integration/targets/docker_network_facts/aliases @@ -0,0 +1,5 @@ +shippable/posix/group2 +skip/osx +skip/freebsd +destructive +skip/rhel8.0 diff --git a/test/integration/targets/docker_network_facts/meta/main.yml b/test/integration/targets/docker_network_facts/meta/main.yml new file mode 100644 index 00000000000..07da8c6ddae --- /dev/null +++ b/test/integration/targets/docker_network_facts/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_docker diff --git a/test/integration/targets/docker_network_facts/tasks/main.yml b/test/integration/targets/docker_network_facts/tasks/main.yml new file mode 100644 index 00000000000..73d17968703 --- /dev/null +++ b/test/integration/targets/docker_network_facts/tasks/main.yml @@ -0,0 +1,60 @@ +--- +- block: + - name: Create random network name + set_fact: + nname: "{{ 'ansible-test-%0x' % ((2**32) | random) }}" + + - name: Make sure network is not there + docker_network: + name: "{{ nname }}" + state: absent + force: yes + + - name: Inspect a non-present network + docker_network_facts: + name: "{{ nname }}" + register: result + + - assert: + that: + - "not result.exists" + - "'docker_network' in result" + - "result.docker_network is none" + + - name: Make sure network exists + docker_network: + name: "{{ nname }}" + state: present + + - name: Inspect a present network + docker_network_facts: + name: "{{ nname }}" + register: result + - name: Dump docker_network_facts result + debug: var=result + + - name: "Comparison: use 'docker network inspect'" + command: docker network inspect "{{ nname }}" + register: docker_inspect + - set_fact: + docker_inspect_result: "{{ docker_inspect.stdout | from_json }}" + - name: Dump docker inspect result + debug: var=docker_inspect_result + + - name: Cleanup + docker_network: + name: "{{ nname }}" + state: absent + force: yes + + - assert: + that: + - result.exists + - "'docker_network' in result" + - "result.docker_network" + - "result.docker_network == docker_inspect_result[0]" + + when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.21', '>=') + +- fail: msg="Too old docker / docker-py version to run docker_network_facts tests!" + when: not(docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.21', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)