forked from CCCHH/ansible-infra
Vendor Galaxy Roles and Collections
This commit is contained in:
parent
c1e1897cda
commit
2aed20393f
3553 changed files with 387444 additions and 2 deletions
|
|
@ -0,0 +1,338 @@
|
|||
# Copyright (c) 2018, Stefan Heitmueller <stefan.heitmueller@gmx.com>
|
||||
# Copyright (c) 2018 Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
name: docker_swarm
|
||||
author:
|
||||
- Stefan Heitmüller (@morph027) <stefan.heitmueller@gmx.com>
|
||||
short_description: Ansible dynamic inventory plugin for Docker swarm nodes
|
||||
requirements:
|
||||
- L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 1.10.0
|
||||
extends_documentation_fragment:
|
||||
- ansible.builtin.constructed
|
||||
- community.library_inventory_filtering_v1.inventory_filter
|
||||
description:
|
||||
- Reads inventories from the Docker swarm API.
|
||||
- Uses a YAML configuration file that ends with V(docker_swarm.(yml|yaml\)).
|
||||
- 'The plugin returns following groups of swarm nodes: C(all) - all hosts; C(workers) - all worker nodes; C(managers) -
|
||||
all manager nodes; C(leader) - the swarm leader node; C(nonleaders) - all nodes except the swarm leader.'
|
||||
notes:
|
||||
- The configuration file must be a YAML file whose filename ends with V(docker_swarm.yml) or V(docker_swarm.yaml). Other
|
||||
filenames will not be accepted.
|
||||
options:
|
||||
plugin:
|
||||
description: The name of this plugin, it should always be set to V(community.docker.docker_swarm) for this plugin to recognize
|
||||
it as its own.
|
||||
type: str
|
||||
required: true
|
||||
choices: [docker_swarm, community.docker.docker_swarm]
|
||||
docker_host:
|
||||
description:
|
||||
- Socket of a Docker swarm manager node (C(tcp), C(unix)).
|
||||
- Use V(unix:///var/run/docker.sock) to connect through a local socket.
|
||||
type: str
|
||||
required: true
|
||||
aliases: [docker_url]
|
||||
verbose_output:
|
||||
description: Toggle to (not) include all available nodes metadata (for example C(Platform), C(Architecture), C(OS), C(EngineVersion)).
|
||||
type: bool
|
||||
default: true
|
||||
tls:
|
||||
description: Connect using TLS without verifying the authenticity of the Docker host server.
|
||||
type: bool
|
||||
default: false
|
||||
validate_certs:
|
||||
description: Toggle if connecting using TLS with or without verifying the authenticity of the Docker host server.
|
||||
type: bool
|
||||
default: false
|
||||
aliases: [tls_verify]
|
||||
client_key:
|
||||
description: Path to the client's TLS key file.
|
||||
type: path
|
||||
aliases: [tls_client_key, key_path]
|
||||
ca_path:
|
||||
description:
|
||||
- Use a CA certificate when performing server verification by providing the path to a CA certificate file.
|
||||
- This option was called O(ca_cert) and got renamed to O(ca_path) in community.docker 3.6.0. The old name has been added
|
||||
as an alias and can still be used.
|
||||
type: path
|
||||
aliases: [ca_cert, tls_ca_cert, cacert_path]
|
||||
client_cert:
|
||||
description: Path to the client's TLS certificate file.
|
||||
type: path
|
||||
aliases: [tls_client_cert, cert_path]
|
||||
tls_hostname:
|
||||
description: When verifying the authenticity of the Docker host server, provide the expected name of the server.
|
||||
type: str
|
||||
api_version:
|
||||
description:
|
||||
- The version of the Docker API running on the Docker Host.
|
||||
- Defaults to the latest version of the API supported by Docker SDK for Python.
|
||||
type: str
|
||||
aliases: [docker_api_version]
|
||||
timeout:
|
||||
description:
|
||||
- The maximum amount of time in seconds to wait on a response from the API.
|
||||
- If the value is not specified in the task, the value of environment variable E(DOCKER_TIMEOUT). will be used instead.
|
||||
If the environment variable is not set, the default value will be used.
|
||||
type: int
|
||||
default: 60
|
||||
aliases: [time_out]
|
||||
use_ssh_client:
|
||||
description:
|
||||
- For SSH transports, use the C(ssh) CLI tool instead of paramiko.
|
||||
- Requires Docker SDK for Python 4.4.0 or newer.
|
||||
type: bool
|
||||
default: false
|
||||
version_added: 1.5.0
|
||||
include_host_uri:
|
||||
description: Toggle to return the additional attribute C(ansible_host_uri) which contains the URI of the swarm leader
|
||||
in format of V(tcp://172.16.0.1:2376). This value may be used without additional modification as value of option O(docker_host)
|
||||
in Docker Swarm modules when connecting through the API. The port always defaults to V(2376).
|
||||
type: bool
|
||||
default: false
|
||||
include_host_uri_port:
|
||||
description: Override the detected port number included in C(ansible_host_uri).
|
||||
type: int
|
||||
filters:
|
||||
version_added: 3.5.0
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
---
|
||||
# Minimal example using local docker
|
||||
plugin: community.docker.docker_swarm
|
||||
docker_host: unix:///var/run/docker.sock
|
||||
|
||||
---
|
||||
# Minimal example using remote docker
|
||||
plugin: community.docker.docker_swarm
|
||||
docker_host: tcp://my-docker-host:2375
|
||||
|
||||
---
|
||||
# Example using remote docker with unverified TLS
|
||||
plugin: community.docker.docker_swarm
|
||||
docker_host: tcp://my-docker-host:2376
|
||||
tls: true
|
||||
|
||||
---
|
||||
# Example using remote docker with verified TLS and client certificate verification
|
||||
plugin: community.docker.docker_swarm
|
||||
docker_host: tcp://my-docker-host:2376
|
||||
validate_certs: true
|
||||
ca_path: /somewhere/ca.pem
|
||||
client_key: /somewhere/key.pem
|
||||
client_cert: /somewhere/cert.pem
|
||||
|
||||
---
|
||||
# Example using constructed features to create groups and set ansible_host
|
||||
plugin: community.docker.docker_swarm
|
||||
docker_host: tcp://my-docker-host:2375
|
||||
strict: false
|
||||
keyed_groups:
|
||||
# add for example x86_64 hosts to an arch_x86_64 group
|
||||
- prefix: arch
|
||||
key: 'Description.Platform.Architecture'
|
||||
# add for example linux hosts to an os_linux group
|
||||
- prefix: os
|
||||
key: 'Description.Platform.OS'
|
||||
# create a group per node label
|
||||
# for exomple a node labeled w/ "production" ends up in group "label_production"
|
||||
# hint: labels containing special characters will be converted to safe names
|
||||
- key: 'Spec.Labels'
|
||||
prefix: label
|
||||
"""
|
||||
|
||||
import typing as t
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.parsing.utils.addresses import parse_address
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
|
||||
from ansible_collections.community.library_inventory_filtering_v1.plugins.plugin_utils.inventory_filter import (
|
||||
filter_host,
|
||||
parse_filters,
|
||||
)
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._common import (
|
||||
get_connect_params,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._util import (
|
||||
update_tls_hostname,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.plugin_utils._unsafe import (
|
||||
make_unsafe,
|
||||
)
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from ansible.inventory.data import InventoryData
|
||||
from ansible.parsing.dataloader import DataLoader
|
||||
|
||||
|
||||
try:
|
||||
import docker
|
||||
|
||||
HAS_DOCKER = True
|
||||
except ImportError:
|
||||
HAS_DOCKER = False
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
"""Host inventory parser for ansible using Docker swarm as source."""
|
||||
|
||||
NAME = "community.docker.docker_swarm"
|
||||
|
||||
def _fail(self, msg: str) -> t.NoReturn:
|
||||
raise AnsibleError(msg)
|
||||
|
||||
def _populate(self) -> None:
|
||||
if self.inventory is None:
|
||||
raise AssertionError("Inventory must be there")
|
||||
|
||||
raw_params = {
|
||||
"docker_host": self.get_option("docker_host"),
|
||||
"tls": self.get_option("tls"),
|
||||
"tls_verify": self.get_option("validate_certs"),
|
||||
"key_path": self.get_option("client_key"),
|
||||
"cacert_path": self.get_option("ca_path"),
|
||||
"cert_path": self.get_option("client_cert"),
|
||||
"tls_hostname": self.get_option("tls_hostname"),
|
||||
"api_version": self.get_option("api_version"),
|
||||
"timeout": self.get_option("timeout"),
|
||||
"use_ssh_client": self.get_option("use_ssh_client"),
|
||||
"debug": None,
|
||||
}
|
||||
update_tls_hostname(raw_params)
|
||||
connect_params = get_connect_params(raw_params, fail_function=self._fail)
|
||||
client = docker.DockerClient(**connect_params)
|
||||
self.inventory.add_group("all")
|
||||
self.inventory.add_group("manager")
|
||||
self.inventory.add_group("worker")
|
||||
self.inventory.add_group("leader")
|
||||
self.inventory.add_group("nonleaders")
|
||||
|
||||
filters = parse_filters(self.get_option("filters"))
|
||||
|
||||
if self.get_option("include_host_uri"):
|
||||
if self.get_option("include_host_uri_port"):
|
||||
host_uri_port = str(self.get_option("include_host_uri_port"))
|
||||
elif self.get_option("tls") or self.get_option("validate_certs"):
|
||||
host_uri_port = "2376"
|
||||
else:
|
||||
host_uri_port = "2375"
|
||||
|
||||
try:
|
||||
nodes = client.nodes.list()
|
||||
for node in nodes:
|
||||
node_attrs = client.nodes.get(node.id).attrs
|
||||
unsafe_node_attrs = make_unsafe(node_attrs)
|
||||
if not filter_host(
|
||||
self, unsafe_node_attrs["ID"], unsafe_node_attrs, filters
|
||||
):
|
||||
continue
|
||||
self.inventory.add_host(unsafe_node_attrs["ID"])
|
||||
self.inventory.add_host(
|
||||
unsafe_node_attrs["ID"], group=unsafe_node_attrs["Spec"]["Role"]
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
unsafe_node_attrs["ID"],
|
||||
"ansible_host",
|
||||
unsafe_node_attrs["Status"]["Addr"],
|
||||
)
|
||||
if self.get_option("include_host_uri"):
|
||||
self.inventory.set_variable(
|
||||
unsafe_node_attrs["ID"],
|
||||
"ansible_host_uri",
|
||||
make_unsafe(
|
||||
"tcp://"
|
||||
+ unsafe_node_attrs["Status"]["Addr"]
|
||||
+ ":"
|
||||
+ host_uri_port
|
||||
),
|
||||
)
|
||||
if self.get_option("verbose_output"):
|
||||
self.inventory.set_variable(
|
||||
unsafe_node_attrs["ID"],
|
||||
"docker_swarm_node_attributes",
|
||||
unsafe_node_attrs,
|
||||
)
|
||||
if "ManagerStatus" in unsafe_node_attrs:
|
||||
if unsafe_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
|
||||
swarm_leader_ip = (
|
||||
parse_address(node_attrs["ManagerStatus"]["Addr"])[0]
|
||||
or unsafe_node_attrs["Status"]["Addr"]
|
||||
)
|
||||
if self.get_option("include_host_uri"):
|
||||
self.inventory.set_variable(
|
||||
unsafe_node_attrs["ID"],
|
||||
"ansible_host_uri",
|
||||
make_unsafe(
|
||||
"tcp://" + swarm_leader_ip + ":" + host_uri_port
|
||||
),
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
unsafe_node_attrs["ID"],
|
||||
"ansible_host",
|
||||
make_unsafe(swarm_leader_ip),
|
||||
)
|
||||
self.inventory.add_host(unsafe_node_attrs["ID"], group="leader")
|
||||
else:
|
||||
self.inventory.add_host(
|
||||
unsafe_node_attrs["ID"], group="nonleaders"
|
||||
)
|
||||
else:
|
||||
self.inventory.add_host(unsafe_node_attrs["ID"], group="nonleaders")
|
||||
# Use constructed if applicable
|
||||
strict = self.get_option("strict")
|
||||
# Composed variables
|
||||
self._set_composite_vars(
|
||||
self.get_option("compose"),
|
||||
unsafe_node_attrs,
|
||||
unsafe_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"),
|
||||
unsafe_node_attrs,
|
||||
unsafe_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"),
|
||||
unsafe_node_attrs,
|
||||
unsafe_node_attrs["ID"],
|
||||
strict=strict,
|
||||
)
|
||||
except Exception as e:
|
||||
raise AnsibleError(
|
||||
f"Unable to fetch hosts from Docker swarm API, this was the original exception: {e}"
|
||||
) from e
|
||||
|
||||
def verify_file(self, path: str) -> bool:
|
||||
"""Return the possibly of a file being consumable by this plugin."""
|
||||
return super().verify_file(path) and path.endswith(
|
||||
("docker_swarm.yaml", "docker_swarm.yml")
|
||||
)
|
||||
|
||||
def parse(
|
||||
self,
|
||||
inventory: InventoryData,
|
||||
loader: DataLoader,
|
||||
path: str,
|
||||
cache: bool = True,
|
||||
) -> None:
|
||||
if not HAS_DOCKER:
|
||||
raise AnsibleError(
|
||||
"The Docker swarm dynamic inventory plugin requires the Docker SDK for Python: "
|
||||
"https://github.com/docker/docker-py."
|
||||
)
|
||||
super().parse(inventory, loader, path, cache)
|
||||
self._read_config_data(path)
|
||||
self._populate()
|
||||
Loading…
Add table
Add a link
Reference in a new issue