mirror of
https://github.com/ansible-collections/community.docker.git
synced 2026-07-29 11:55:04 +00:00
Docker inventory plugin (#61)
* Began with docker inventory plugin. * Linting. * Improve plugin, add basic unit tests. * Linting. * Add integration test. * Adjust tests to case that there are more containers. * There can be stopped containers. ci_coverage * docker -> docker_containers
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
shippable/posix/group4
|
||||
destructive
|
||||
needs/root
|
||||
@@ -0,0 +1,2 @@
|
||||
plugin: community.docker.docker_containers
|
||||
docker_host: unix://var/run/docker.sock
|
||||
@@ -0,0 +1,6 @@
|
||||
plugin: community.docker.docker_containers
|
||||
docker_host: unix://var/run/docker.sock
|
||||
connection_type: ssh
|
||||
verbose_output: true
|
||||
add_legacy_groups: true
|
||||
default_ip: 1.2.3.4
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
dependencies:
|
||||
- setup_docker
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
- hosts: 127.0.0.1
|
||||
connection: local
|
||||
gather_facts: yes
|
||||
tasks:
|
||||
- name: remove docker containers
|
||||
docker_container:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
force_kill: yes
|
||||
loop:
|
||||
- ansible-test-docker-inventory-container-1
|
||||
- ansible-test-docker-inventory-container-2
|
||||
|
||||
- name: remove docker pagkages
|
||||
action: "{{ ansible_facts.pkg_mgr }}"
|
||||
args:
|
||||
name:
|
||||
- docker
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
state: absent
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
- hosts: 127.0.0.1
|
||||
connection: local
|
||||
vars:
|
||||
docker_skip_cleanup: yes
|
||||
|
||||
tasks:
|
||||
- name: Setup docker
|
||||
import_role:
|
||||
name: setup_docker
|
||||
|
||||
- name: Start containers
|
||||
docker_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "{{ docker_test_image_alpine }}"
|
||||
state: started
|
||||
command: '/bin/sh -c "sleep 10m"'
|
||||
published_ports:
|
||||
- 22/tcp
|
||||
loop:
|
||||
- name: ansible-test-docker-inventory-container-1
|
||||
- name: ansible-test-docker-inventory-container-2
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
- hosts: 127.0.0.1
|
||||
connection: local # otherwise Ansible will complain that it cannot connect via ssh to 127.0.0.1:22
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Show all groups
|
||||
debug:
|
||||
var: groups
|
||||
- name: Make sure that the default groups are there, but no others
|
||||
assert:
|
||||
that:
|
||||
- groups.all | length >= 2
|
||||
- groups.ungrouped | length >= 2
|
||||
- groups | length == 2
|
||||
|
||||
- hosts: all
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- when:
|
||||
# When the integration tests are run inside a docker container, there
|
||||
# will be other containers.
|
||||
- inventory_hostname.startswith('ansible-test-docker-inventory-container-')
|
||||
block:
|
||||
|
||||
- name: Run raw command
|
||||
raw: ls /
|
||||
register: output
|
||||
|
||||
- name: Check whether we have some directories we expect in the output
|
||||
assert:
|
||||
that:
|
||||
- "'bin' in output.stdout_lines"
|
||||
- "'dev' in output.stdout_lines"
|
||||
- "'lib' in output.stdout_lines"
|
||||
- "'proc' in output.stdout_lines"
|
||||
- "'sys' in output.stdout_lines"
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
- hosts: 127.0.0.1
|
||||
connection: local # otherwise Ansible will complain that it cannot connect via ssh to 127.0.0.1:22
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Show all groups
|
||||
debug:
|
||||
var: groups
|
||||
- name: Load variables
|
||||
include_vars: ../../setup_docker/vars/main.yml
|
||||
- name: Make sure that the expected groups are there
|
||||
assert:
|
||||
that:
|
||||
- groups.all | length >= 2
|
||||
- groups.ungrouped | length >= 0
|
||||
- groups.running | length >= 2
|
||||
- groups.stopped | length >= 0
|
||||
- groups['image_' ~ docker_test_image_alpine] | length == 2
|
||||
- groups['ansible-test-docker-inventory-container-1'] | length == 1
|
||||
- groups['ansible-test-docker-inventory-container-2'] | length == 1
|
||||
- groups['unix://var/run/docker.sock'] | length >= 2
|
||||
- groups | length >= 12
|
||||
# The four additional groups are IDs and short IDs of the containers.
|
||||
# When the integration tests are run inside a docker container, there
|
||||
# will be more groups (for the additional container(s)).
|
||||
|
||||
- hosts: all
|
||||
# We don't really want to connect to the nodes, since we have no SSH daemon running on them
|
||||
connection: local
|
||||
vars:
|
||||
ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Show all variables
|
||||
debug:
|
||||
var: hostvars[inventory_hostname]
|
||||
- name: Make sure SSH is set up
|
||||
assert:
|
||||
that:
|
||||
- ansible_ssh_host == '1.2.3.4'
|
||||
- ansible_ssh_port == docker_networksettings.Ports['22/tcp'][0].HostPort
|
||||
when:
|
||||
# When the integration tests are run inside a docker container, there
|
||||
# will be other containers.
|
||||
- inventory_hostname.startswith('ansible-test-docker-inventory-container-')
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
[[ -n "$DEBUG" || -n "$ANSIBLE_DEBUG" ]] && set -x
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
cleanup() {
|
||||
echo "Cleanup"
|
||||
ansible-playbook playbooks/docker_cleanup.yml
|
||||
echo "Done"
|
||||
}
|
||||
|
||||
trap cleanup INT TERM EXIT
|
||||
|
||||
echo "Setup"
|
||||
ANSIBLE_ROLES_PATH=.. ansible-playbook playbooks/docker_setup.yml
|
||||
|
||||
echo "Test docker_containers inventory 1"
|
||||
ansible-playbook -i inventory_1.docker.yml playbooks/test_inventory_1.yml
|
||||
|
||||
echo "Test docker_containers inventory 2"
|
||||
ansible-playbook -i inventory_2.docker.yml playbooks/test_inventory_2.yml
|
||||
@@ -0,0 +1,228 @@
|
||||
# Copyright (c), Felix Fontein <felix@fontein.de>, 2020
|
||||
# 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
|
||||
|
||||
|
||||
import json
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
from mock import MagicMock
|
||||
|
||||
from ansible import constants as C
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.inventory.data import InventoryData
|
||||
from ansible.inventory.manager import InventoryManager
|
||||
|
||||
from ansible_collections.community.docker.plugins.inventory.docker_containers import InventoryModule
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def inventory():
|
||||
r = InventoryModule()
|
||||
r.inventory = InventoryData()
|
||||
return r
|
||||
|
||||
|
||||
LOVING_THARP = {
|
||||
'Id': '7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a',
|
||||
'Name': '/loving_tharp',
|
||||
'Image': 'sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385',
|
||||
'State': {
|
||||
'Running': True,
|
||||
},
|
||||
'Config': {
|
||||
'Image': 'quay.io/ansible/ubuntu1804-test-container:1.21.0',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
LOVING_THARP_STACK = {
|
||||
'Id': '7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a',
|
||||
'Name': '/loving_tharp',
|
||||
'Image': 'sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385',
|
||||
'State': {
|
||||
'Running': True,
|
||||
},
|
||||
'Config': {
|
||||
'Image': 'quay.io/ansible/ubuntu1804-test-container:1.21.0',
|
||||
'Labels': {
|
||||
'com.docker.stack.namespace': 'my_stack',
|
||||
},
|
||||
},
|
||||
'NetworkSettings': {
|
||||
'Ports': {
|
||||
'22/tcp': [
|
||||
{
|
||||
'HostIp': '0.0.0.0',
|
||||
'HostPort': '32802'
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
LOVING_THARP_SERVICE = {
|
||||
'Id': '7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a',
|
||||
'Name': '/loving_tharp',
|
||||
'Image': 'sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385',
|
||||
'State': {
|
||||
'Running': True,
|
||||
},
|
||||
'Config': {
|
||||
'Image': 'quay.io/ansible/ubuntu1804-test-container:1.21.0',
|
||||
'Labels': {
|
||||
'com.docker.swarm.service.name': 'my_service',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def create_get_option(options, default=False):
|
||||
def get_option(option):
|
||||
if option in options:
|
||||
return options[option]
|
||||
return default
|
||||
|
||||
return get_option
|
||||
|
||||
|
||||
class FakeClient(object):
|
||||
def __init__(self, *hosts):
|
||||
self.hosts = dict()
|
||||
self.list_reply = []
|
||||
for host in hosts:
|
||||
self.list_reply.append({
|
||||
'Id': host['Id'],
|
||||
'Names': [host['Name']] if host['Name'] else [],
|
||||
'Image': host['Config']['Image'],
|
||||
'ImageId': host['Image'],
|
||||
})
|
||||
self.hosts[host['Name']] = host
|
||||
self.hosts[host['Id']] = host
|
||||
|
||||
def containers(self, all=False):
|
||||
return list(self.list_reply)
|
||||
|
||||
def inspect_container(self, id):
|
||||
return self.hosts[id]
|
||||
|
||||
def port(self, container, port):
|
||||
host = self.hosts[container['Id']]
|
||||
network_settings = host.get('NetworkSettings') or dict()
|
||||
ports = network_settings.get('Ports') or dict()
|
||||
return ports.get('{0}/tcp'.format(port)) or []
|
||||
|
||||
|
||||
def test_populate(inventory, mocker):
|
||||
client = FakeClient(LOVING_THARP)
|
||||
|
||||
inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
|
||||
'verbose_output': True,
|
||||
'connection_type': 'docker-api',
|
||||
'add_legacy_groups': False,
|
||||
'compose': {},
|
||||
'groups': {},
|
||||
'keyed_groups': {},
|
||||
}))
|
||||
inventory._populate(client)
|
||||
|
||||
host_1 = inventory.inventory.get_host('loving_tharp')
|
||||
host_1_vars = host_1.get_vars()
|
||||
|
||||
assert host_1_vars['ansible_host'] == 'loving_tharp'
|
||||
assert host_1_vars['ansible_connection'] == 'community.docker.docker_api'
|
||||
assert 'ansible_ssh_host' not in host_1_vars
|
||||
assert 'ansible_ssh_port' not in host_1_vars
|
||||
assert 'docker_state' in host_1_vars
|
||||
assert 'docker_config' in host_1_vars
|
||||
assert 'docker_image' in host_1_vars
|
||||
|
||||
assert len(inventory.inventory.groups['ungrouped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['all'].hosts) == 0
|
||||
assert len(inventory.inventory.groups) == 2
|
||||
assert len(inventory.inventory.hosts) == 1
|
||||
|
||||
|
||||
def test_populate_service(inventory, mocker):
|
||||
client = FakeClient(LOVING_THARP_SERVICE)
|
||||
|
||||
inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
|
||||
'verbose_output': False,
|
||||
'connection_type': 'docker-cli',
|
||||
'add_legacy_groups': True,
|
||||
'compose': {},
|
||||
'groups': {},
|
||||
'keyed_groups': {},
|
||||
'docker_host': 'unix://var/run/docker.sock',
|
||||
}))
|
||||
inventory._populate(client)
|
||||
|
||||
host_1 = inventory.inventory.get_host('loving_tharp')
|
||||
host_1_vars = host_1.get_vars()
|
||||
|
||||
assert host_1_vars['ansible_host'] == 'loving_tharp'
|
||||
assert host_1_vars['ansible_connection'] == 'community.docker.docker'
|
||||
assert 'ansible_ssh_host' not in host_1_vars
|
||||
assert 'ansible_ssh_port' not in host_1_vars
|
||||
assert 'docker_state' not in host_1_vars
|
||||
assert 'docker_config' not in host_1_vars
|
||||
assert 'docker_image' not in host_1_vars
|
||||
|
||||
assert len(inventory.inventory.groups['ungrouped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['all'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['7bd547963679e'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['image_quay.io/ansible/ubuntu1804-test-container:1.21.0'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['loving_tharp'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['running'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['stopped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['service_my_service'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['unix://var/run/docker.sock'].hosts) == 1
|
||||
assert len(inventory.inventory.groups) == 10
|
||||
assert len(inventory.inventory.hosts) == 1
|
||||
|
||||
|
||||
def test_populate_stack(inventory, mocker):
|
||||
client = FakeClient(LOVING_THARP_STACK)
|
||||
|
||||
inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
|
||||
'verbose_output': False,
|
||||
'connection_type': 'ssh',
|
||||
'add_legacy_groups': True,
|
||||
'compose': {},
|
||||
'groups': {},
|
||||
'keyed_groups': {},
|
||||
'docker_host': 'unix://var/run/docker.sock',
|
||||
'default_ip': '127.0.0.1',
|
||||
'private_ssh_port': 22,
|
||||
}))
|
||||
inventory._populate(client)
|
||||
|
||||
host_1 = inventory.inventory.get_host('loving_tharp')
|
||||
host_1_vars = host_1.get_vars()
|
||||
|
||||
assert host_1_vars['ansible_ssh_host'] == '127.0.0.1'
|
||||
assert host_1_vars['ansible_ssh_port'] == '32802'
|
||||
assert 'ansible_host' not in host_1_vars
|
||||
assert 'ansible_connection' not in host_1_vars
|
||||
assert 'docker_state' not in host_1_vars
|
||||
assert 'docker_config' not in host_1_vars
|
||||
assert 'docker_image' not in host_1_vars
|
||||
|
||||
assert len(inventory.inventory.groups['ungrouped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['all'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['7bd547963679e'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['image_quay.io/ansible/ubuntu1804-test-container:1.21.0'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['loving_tharp'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['running'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['stopped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['stack_my_stack'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['unix://var/run/docker.sock'].hosts) == 1
|
||||
assert len(inventory.inventory.groups) == 10
|
||||
assert len(inventory.inventory.hosts) == 1
|
||||
Reference in New Issue
Block a user