docker_swarm inventory plugin - new attribute with parsed node URI (#53894)

* * Adding new attribute that contains an URI which may be used in other docker swarm modules

* Change host_uri to include_host_uri parameter name

* Adding port detection/override

* Small fixes

* Some general PEP8 adjustments for better code readability

* Changing the parameter type description for clearance
pull/53913/head
Piotr Wojciechowski 5 years ago committed by ansibot
parent 259b2e06a4
commit 955da2a095

@ -56,6 +56,16 @@ DOCUMENTATION = '''
tls_hostname:
description: When verifying the authenticity of the Docker Host server, provide the expected name of the server.
type: str
include_host_uri:
description: Toggle to return the additional attribute I(ansible_host_uri) which contains the URI of the
swarm leader in format of M(tcp://172.16.0.1:2376). This value may be used without additional
modification as value of option I(docker_host) in Docker Swarm modules when connecting via API.
The port always defaults to M(2376).
type: bool
default: no
include_host_uri_port:
description: Override the detected port number included in I(ansible_host_uri)
type: int
'''
EXAMPLES = '''
@ -125,7 +135,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
def _get_tls_connect_params(self):
if self.get_option('tls') and self.get_option('cert_path') and self.get_option('key_path'):
# TLS with certs and no host verification
tls_config = self._get_tls_config(client_cert=(self.get_option('cert_path'), self.get_option('key_path')),
tls_config = self._get_tls_config(client_cert=(self.get_option('cert_path'),
self.get_option('key_path')),
verify=False)
return tls_config
@ -137,12 +148,14 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
if self.get_option('tls_verify') and self.get_option('cert_path') and self.get_option('key_path'):
# TLS with certs and host verification
if self.get_option('cacert_path'):
tls_config = self._get_tls_config(client_cert=(self.get_option('cert_path'), self.get_option('key_path')),
tls_config = self._get_tls_config(client_cert=(self.get_option('cert_path'),
self.get_option('key_path')),
ca_cert=self.get_option('cacert_path'),
verify=True,
assert_hostname=self.get_option('tls_hostname'))
else:
tls_config = self._get_tls_config(client_cert=(self.get_option('cert_path'), self.get_option('key_path')),
tls_config = self._get_tls_config(client_cert=(self.get_option('cert_path'),
self.get_option('key_path')),
verify=True,
assert_hostname=self.get_option('tls_hostname'))
@ -165,37 +178,65 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
return None
def _populate(self):
self.client = docker.DockerClient(base_url=self.get_option('host'), tls=self._get_tls_connect_params())
self.client = docker.DockerClient(base_url=self.get_option('host'),
tls=self._get_tls_connect_params())
self.inventory.add_group('all')
self.inventory.add_group('manager')
self.inventory.add_group('worker')
self.inventory.add_group('leader')
if self.get_option('include_host_uri', True):
if self.get_option('include_host_uri_port'):
host_uri_port = self.get_option('include_host_uri_port')
elif self.get_option('tls') or self.get_option('tls_verify'):
host_uri_port = "2376"
else:
host_uri_port = "2375"
try:
self.nodes = self.client.nodes.list()
for self.node in self.nodes:
self.node_attrs = self.client.nodes.get(self.node.id).attrs
self.inventory.add_host(self.node_attrs['ID'])
self.inventory.add_host(self.node_attrs['ID'], group=self.node_attrs['Spec']['Role'])
self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host', self.node_attrs['Status']['Addr'])
self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host',
self.node_attrs['Status']['Addr'])
if self.get_option('include_host_uri', True):
self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host_uri',
"tcp://" + self.node_attrs['Status']['Addr'] + ":" + host_uri_port)
if self.get_option('verbose_output', True):
self.inventory.set_variable(self.node_attrs['ID'], 'docker_swarm_node_attributes', self.node_attrs)
if 'ManagerStatus' in self.node_attrs:
if self.node_attrs['ManagerStatus'].get('Leader'):
# This is workaround of bug in Docker when in some cases the Leader IP is 0.0.0.0
# Check moby/moby#35437 for details
self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host',
parse_address(self.node_attrs['ManagerStatus']['Addr'])[0])
swarm_leader_ip = parse_address(self.node_attrs['ManagerStatus']['Addr'])[0] or \
self.node_attrs['Status']['Addr']
if self.get_option('include_host_uri', True):
self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host_uri', "tcp://" +
swarm_leader_ip + ":" + host_uri_port)
self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host', swarm_leader_ip)
self.inventory.add_host(self.node_attrs['ID'], group='leader')
# Use constructed if applicable
strict = self.get_option('strict')
# Composed variables
self._set_composite_vars(self.get_option('compose'), self.node_attrs, self.node_attrs['ID'], strict=strict)
self._set_composite_vars(self.get_option('compose'),
self.node_attrs,
self.node_attrs['ID'],
strict=strict)
# Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
self._add_host_to_composed_groups(self.get_option('groups'), self.node_attrs, self.node_attrs['ID'], strict=strict)
self._add_host_to_composed_groups(self.get_option('groups'),
self.node_attrs,
self.node_attrs['ID'],
strict=strict)
# Create groups based on variable values and add the corresponding hosts to it
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), self.node_attrs, self.node_attrs['ID'], strict=strict)
self._add_host_to_keyed_groups(self.get_option('keyed_groups'),
self.node_attrs,
self.node_attrs['ID'],
strict=strict)
except Exception as e:
raise AnsibleError('Unable to fetch hosts from Docker swarm API, this was the original exception: %s' % to_native(e))
raise AnsibleError('Unable to fetch hosts from Docker swarm API, this was the original exception: %s' %
to_native(e))
def verify_file(self, path):
"""Return the possibly of a file being consumable by this plugin."""
@ -205,7 +246,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
def parse(self, inventory, loader, path, cache=True):
if not HAS_DOCKER:
raise AnsibleError('The Docker swarm dynamic inventory plugin requires the Docker SDK for Python: https://github.com/docker/docker-py.')
raise AnsibleError('The Docker swarm dynamic inventory plugin requires the Docker SDK for Python: '
'https://github.com/docker/docker-py.')
super(InventoryModule, self).parse(inventory, loader, path, cache)
self._read_config_data(path)
self._populate()

Loading…
Cancel
Save