summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPilou <pierre-louis@libregerbil.fr>2018-09-27 00:16:54 +0200
committeransibot <ansibot@users.noreply.github.com>2018-09-26 18:16:54 -0400
commit2fd18c77aef019a34b79b12a58fcbe40272cda8d (patch)
tree4a31a0f0d3cbb4ab97aabc30b67821e287952b20
parent241b04f7e9ac075196ef9078efaf960866e2117e (diff)
downloadansible-2fd18c77aef019a34b79b12a58fcbe40272cda8d.tar.gz
openshift inventory plugin: fix exception when auth fails (#45826)
* openshift inventory: fix exception when auth fails Fix 'ForbiddenError' object has no attribute 'message': [WARNING]: * Failed to parse test.yml with openshift plugin: 'ForbiddenError' object has no attribute 'message' File "ansible/lib/ansible/inventory/manager.py", line 270, in parse_source plugin.parse(self._inventory, self._loader, source, cache=cache) File "ansible/lib/ansible/plugins/inventory/openshift.py", line 122, in parse self.setup(config_data, cache, cache_key) File "ansible/lib/ansible/module_utils/k8s/inventory.py", line 58, in setup self.fetch_objects(connections) File "ansible/lib/ansible/module_utils/k8s/inventory.py", line 250, in fetch_objects super(OpenShiftInventoryHelper, self).fetch_objects(connections) File "ansible/lib/ansible/module_utils/k8s/inventory.py", line 81, in fetch_objects namespaces = self.get_available_namespaces(client) File "ansible/lib/ansible/module_utils/k8s/inventory.py", line 95, in get_available_namespaces raise K8sInventoryException('Error fetching Namespace list: {0}'.format(exc.message)) Don't try to get 'message' attribute from: - K8sInventoryException instances - Exception instances - KubernetesException instances (because KubernetesException can be Exception) * move k8s/OpenShift inventory plugin dedicated code inventory plugin specific code should not be located in lib/ansible/module_utils directory. Then ansible.utils methods can be reused (for example Display). * Remove unused class variables 'helper' unused since 4d77878654e867c23d5f6c61422bdae7120393bc.
-rw-r--r--lib/ansible/module_utils/k8s/common.py3
-rw-r--r--lib/ansible/module_utils/k8s/inventory.py316
-rw-r--r--lib/ansible/module_utils/k8s/scale.py6
-rw-r--r--lib/ansible/plugins/inventory/k8s.py234
-rw-r--r--lib/ansible/plugins/inventory/openshift.py86
5 files changed, 315 insertions, 330 deletions
diff --git a/lib/ansible/module_utils/k8s/common.py b/lib/ansible/module_utils/k8s/common.py
index ae82f32370..17be0b297f 100644
--- a/lib/ansible/module_utils/k8s/common.py
+++ b/lib/ansible/module_utils/k8s/common.py
@@ -17,8 +17,9 @@
from __future__ import absolute_import, division, print_function
-import os
import copy
+import json
+import os
from ansible.module_utils.basic import AnsibleModule
diff --git a/lib/ansible/module_utils/k8s/inventory.py b/lib/ansible/module_utils/k8s/inventory.py
deleted file mode 100644
index 8cd954d020..0000000000
--- a/lib/ansible/module_utils/k8s/inventory.py
+++ /dev/null
@@ -1,316 +0,0 @@
-#
-# Copyright 2018 Red Hat | Ansible
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import absolute_import, division, print_function
-
-from ansible.module_utils.k8s.common import K8sAnsibleMixin, HAS_K8S_MODULE_HELPER
-
-try:
- from ansible.errors import AnsibleError
-except ImportError:
- AnsibleError = Exception
-
-try:
- from openshift.dynamic.exceptions import DynamicApiError
-except ImportError:
- pass
-
-
-class K8sInventoryException(Exception):
- pass
-
-
-class K8sInventoryHelper(K8sAnsibleMixin):
- helper = None
- transport = 'kubectl'
-
- def setup(self, config_data, cache, cache_key):
- connections = config_data.get('connections')
-
- if not HAS_K8S_MODULE_HELPER:
- raise K8sInventoryException(
- "This module requires the OpenShift Python client. Try `pip install openshift`"
- )
-
- source_data = None
- if cache and cache_key in self._cache:
- try:
- source_data = self._cache[cache_key]
- except KeyError:
- pass
-
- if not source_data:
- self.fetch_objects(connections)
-
- def fetch_objects(self, connections):
- client = self.get_api_client()
-
- if connections:
- if not isinstance(connections, list):
- raise K8sInventoryException("Expecting connections to be a list.")
-
- for connection in connections:
- if not isinstance(connection, dict):
- raise K8sInventoryException("Expecting connection to be a dictionary.")
- client = self.get_api_client(**connection)
- name = connection.get('name', self.get_default_host_name(client.configuration.host))
- if connection.get('namespaces'):
- namespaces = connection['namespaces']
- else:
- namespaces = self.get_available_namespaces(client)
- for namespace in namespaces:
- self.get_pods_for_namespace(client, name, namespace)
- self.get_services_for_namespace(client, name, namespace)
- else:
- name = self.get_default_host_name(client.configuration.host)
- namespaces = self.get_available_namespaces(client)
- for namespace in namespaces:
- self.get_pods_for_namespace(client, name, namespace)
- self.get_services_for_namespace(client, name, namespace)
-
- @staticmethod
- def get_default_host_name(host):
- return host.replace('https://', '').replace('http://', '').replace('.', '-').replace(':', '_')
-
- def get_available_namespaces(self, client):
- v1_namespace = client.resources.get(api_version='v1', kind='Namespace')
- try:
- obj = v1_namespace.get()
- except DynamicApiError as exc:
- raise K8sInventoryException('Error fetching Namespace list: {0}'.format(exc.message))
- return [namespace.metadata.name for namespace in obj.items]
-
- def get_pods_for_namespace(self, client, name, namespace):
- v1_pod = client.resources.get(api_version='v1', kind='Pod')
- try:
- obj = v1_pod.get(namespace=namespace)
- except DynamicApiError as exc:
- raise K8sInventoryException('Error fetching Pod list: {0}'.format(exc.message))
-
- namespace_group = 'namespace_{0}'.format(namespace)
- namespace_pods_group = '{0}_pods'.format(namespace_group)
-
- self.inventory.add_group(name)
- self.inventory.add_group(namespace_group)
- self.inventory.add_child(name, namespace_group)
- self.inventory.add_group(namespace_pods_group)
- self.inventory.add_child(namespace_group, namespace_pods_group)
-
- for pod in obj.items:
- pod_name = pod.metadata.name
- pod_groups = []
- pod_labels = {} if not pod.metadata.labels else pod.metadata.labels
- pod_annotations = {} if not pod.metadata.annotations else pod.metadata.annotations
-
- if pod.metadata.labels:
- pod_labels = pod.metadata.labels
- # create a group for each label_value
- for key, value in pod.metadata.labels:
- group_name = 'label_{0}_{1}'.format(key, value)
- if group_name not in pod_groups:
- pod_groups.append(group_name)
- self.inventory.add_group(group_name)
-
- for container in pod.status.containerStatuses:
- # add each pod_container to the namespace group, and to each label_value group
- container_name = '{0}_{1}'.format(pod.metadata.name, container.name)
- self.inventory.add_host(container_name)
- self.inventory.add_child(namespace_pods_group, container_name)
- if pod_groups:
- for group in pod_groups:
- self.inventory.add_child(group, container_name)
-
- # Add hostvars
- self.inventory.set_variable(container_name, 'object_type', 'pod')
- self.inventory.set_variable(container_name, 'labels', pod_labels)
- self.inventory.set_variable(container_name, 'annotations', pod_annotations)
- self.inventory.set_variable(container_name, 'cluster_name', pod.metadata.clusterName)
- self.inventory.set_variable(container_name, 'pod_node_name', pod.spec.nodeName)
- self.inventory.set_variable(container_name, 'pod_name', pod.spec.name)
- self.inventory.set_variable(container_name, 'pod_host_ip', pod.status.hostIP)
- self.inventory.set_variable(container_name, 'pod_phase', pod.status.phase)
- self.inventory.set_variable(container_name, 'pod_ip', pod.status.podIP)
- self.inventory.set_variable(container_name, 'pod_self_link', pod.metadata.selfLink)
- self.inventory.set_variable(container_name, 'pod_resource_version', pod.metadata.resourceVersion)
- self.inventory.set_variable(container_name, 'pod_uid', pod.metadata.uid)
- self.inventory.set_variable(container_name, 'container_name', container.image)
- self.inventory.set_variable(container_name, 'container_image', container.image)
- if container.state.running:
- self.inventory.set_variable(container_name, 'container_state', 'Running')
- if container.state.terminated:
- self.inventory.set_variable(container_name, 'container_state', 'Terminated')
- if container.state.waiting:
- self.inventory.set_variable(container_name, 'container_state', 'Waiting')
- self.inventory.set_variable(container_name, 'container_ready', container.ready)
- self.inventory.set_variable(container_name, 'ansible_remote_tmp', '/tmp/')
- self.inventory.set_variable(container_name, 'ansible_connection', self.transport)
- self.inventory.set_variable(container_name, 'ansible_{0}_pod'.format(self.transport),
- pod_name)
- self.inventory.set_variable(container_name, 'ansible_{0}_container'.format(self.transport),
- container.name)
- self.inventory.set_variable(container_name, 'ansible_{0}_namespace'.format(self.transport),
- namespace)
-
- def get_services_for_namespace(self, client, name, namespace):
- v1_service = client.resources.get(api_version='v1', kind='Service')
- try:
- obj = v1_service.get(namespace=namespace)
- except DynamicApiError as exc:
- raise K8sInventoryException('Error fetching Service list: {0}'.format(exc.message))
-
- namespace_group = 'namespace_{0}'.format(namespace)
- namespace_services_group = '{0}_services'.format(namespace_group)
-
- self.inventory.add_group(name)
- self.inventory.add_group(namespace_group)
- self.inventory.add_child(name, namespace_group)
- self.inventory.add_group(namespace_services_group)
- self.inventory.add_child(namespace_group, namespace_services_group)
-
- for service in obj.items:
- service_name = service.metadata.name
- service_labels = {} if not service.metadata.labels else service.metadata.labels
- service_annotations = {} if not service.metadata.annotations else service.metadata.annotations
-
- self.inventory.add_host(service_name)
-
- if service.metadata.labels:
- # create a group for each label_value
- for key, value in service.metadata.labels:
- group_name = 'label_{0}_{1}'.format(key, value)
- self.inventory.add_group(group_name)
- self.inventory.add_child(group_name, service_name)
-
- try:
- self.inventory.add_child(namespace_services_group, service_name)
- except AnsibleError as e:
- raise
-
- ports = [{'name': port.name,
- 'port': port.port,
- 'protocol': port.protocol,
- 'targetPort': port.targetPort,
- 'nodePort': port.nodePort} for port in service.spec.ports or []]
-
- # add hostvars
- self.inventory.set_variable(service_name, 'object_type', 'service')
- self.inventory.set_variable(service_name, 'labels', service_labels)
- self.inventory.set_variable(service_name, 'annotations', service_annotations)
- self.inventory.set_variable(service_name, 'cluster_name', service.metadata.clusterName)
- self.inventory.set_variable(service_name, 'ports', ports)
- self.inventory.set_variable(service_name, 'type', service.spec.type)
- self.inventory.set_variable(service_name, 'self_link', service.metadata.selfLink)
- self.inventory.set_variable(service_name, 'resource_version', service.metadata.resourceVersion)
- self.inventory.set_variable(service_name, 'uid', service.metadata.uid)
-
- if service.spec.externalTrafficPolicy:
- self.inventory.set_variable(service_name, 'external_traffic_policy',
- service.spec.externalTrafficPolicy)
- if service.spec.externalIPs:
- self.inventory.set_variable(service_name, 'external_ips', service.spec.externalIPs)
-
- if service.spec.externalName:
- self.inventory.set_variable(service_name, 'external_name', service.spec.externalName)
-
- if service.spec.healthCheckNodePort:
- self.inventory.set_variable(service_name, 'health_check_node_port',
- service.spec.healthCheckNodePort)
- if service.spec.loadBalancerIP:
- self.inventory.set_variable(service_name, 'load_balancer_ip',
- service.spec.loadBalancerIP)
- if service.spec.selector:
- self.inventory.set_variable(service_name, 'selector', service.spec.selector)
-
- if hasattr(service.status.loadBalancer, 'ingress') and service.status.loadBalancer.ingress:
- load_balancer = [{'hostname': ingress.hostname,
- 'ip': ingress.ip} for ingress in service.status.loadBalancer.ingress]
- self.inventory.set_variable(service_name, 'load_balancer', load_balancer)
-
-
-class OpenShiftInventoryHelper(K8sInventoryHelper):
- helper = None
- transport = 'oc'
-
- def fetch_objects(self, connections):
- super(OpenShiftInventoryHelper, self).fetch_objects(connections)
- client = self.get_api_client()
-
- if connections:
- for connection in connections:
- client = self.get_api_client(**connection)
- name = connection.get('name', self.get_default_host_name(client.configuration.host))
- if connection.get('namespaces'):
- namespaces = connection['namespaces']
- else:
- namespaces = self.get_available_namespaces(client)
- for namespace in namespaces:
- self.get_routes_for_namespace(client, name, namespace)
- else:
- name = self.get_default_host_name(client.configuration.host)
- namespaces = self.get_available_namespaces(client)
- for namespace in namespaces:
- self.get_routes_for_namespace(client, name, namespace)
-
- def get_routes_for_namespace(self, client, name, namespace):
- v1_route = client.resources.get(api_version='v1', kind='Route')
- try:
- obj = v1_route.get(namespace=namespace)
- except DynamicApiError as exc:
- raise K8sInventoryException('Error fetching Routes list: {0}'.format(exc.message))
-
- namespace_group = 'namespace_{0}'.format(namespace)
- namespace_routes_group = '{0}_routes'.format(namespace_group)
-
- self.inventory.add_group(name)
- self.inventory.add_group(namespace_group)
- self.inventory.add_child(name, namespace_group)
- self.inventory.add_group(namespace_routes_group)
- self.inventory.add_child(namespace_group, namespace_routes_group)
- for route in obj.items:
- route_name = route.metadata.name
- route_labels = {} if not route.metadata.labels else route.metadata.labels
- route_annotations = {} if not route.metadata.annotations else route.metadata.annotations
-
- self.inventory.add_host(route_name)
-
- if route.metadata.labels:
- # create a group for each label_value
- for key, value in route.metadata.labels:
- group_name = 'label_{0}_{1}'.format(key, value)
- self.inventory.add_group(group_name)
- self.inventory.add_child(group_name, route_name)
-
- self.inventory.add_child(namespace_routes_group, route_name)
-
- # add hostvars
- self.inventory.set_variable(route_name, 'labels', route_labels)
- self.inventory.set_variable(route_name, 'annotations', route_annotations)
- self.inventory.set_variable(route_name, 'cluster_name', route.metadata.clusterName)
- self.inventory.set_variable(route_name, 'object_type', 'route')
- self.inventory.set_variable(route_name, 'self_link', route.metadata.selfLink)
- self.inventory.set_variable(route_name, 'resource_version', route.metadata.resourceVersion)
- self.inventory.set_variable(route_name, 'uid', route.metadata.uid)
-
- if route.spec.host:
- self.inventory.set_variable(route_name, 'host', route.spec.host)
-
- if route.spec.path:
- self.inventory.set_variable(route_name, 'path', route.spec.path)
-
- if hasattr(route.spec.port, 'targetPort') and route.spec.port.targetPort:
- self.inventory.set_variable(route_name, 'port', route.spec.port)
diff --git a/lib/ansible/module_utils/k8s/scale.py b/lib/ansible/module_utils/k8s/scale.py
index 9454cb95b2..73d3170046 100644
--- a/lib/ansible/module_utils/k8s/scale.py
+++ b/lib/ansible/module_utils/k8s/scale.py
@@ -70,7 +70,7 @@ class KubernetesAnsibleScaleModule(KubernetesRawModule):
existing = resource.get(name=name, namespace=namespace)
return_attributes['result'] = existing.to_dict()
except KubernetesException as exc:
- self.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc.message),
+ self.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc),
error=exc.value.get('status'))
if self.kind == 'job':
@@ -129,7 +129,7 @@ class KubernetesAnsibleScaleModule(KubernetesRawModule):
resource.scale.patch(body=scale_obj)
except Exception as exc:
self.fail_json(
- msg="Scale request failed: {0}".format(exc.message)
+ msg="Scale request failed: {0}".format(exc)
)
if wait and stream is not None:
@@ -173,7 +173,7 @@ class KubernetesAnsibleScaleModule(KubernetesRawModule):
watcher.stop()
break
except Exception as exc:
- self.fail_json(msg="Exception reading event stream: {0}".format(exc.message))
+ self.fail_json(msg="Exception reading event stream: {0}".format(exc))
if not return_obj:
self.fail_json(msg="Error fetching the patched object. Try a higher wait_timeout value.")
diff --git a/lib/ansible/plugins/inventory/k8s.py b/lib/ansible/plugins/inventory/k8s.py
index d6fcc1e592..6012a12052 100644
--- a/lib/ansible/plugins/inventory/k8s.py
+++ b/lib/ansible/plugins/inventory/k8s.py
@@ -108,15 +108,245 @@ connections:
context: 'awx/192-168-64-4:8443/developer'
'''
+import json
+
+from ansible.errors import AnsibleError
+from ansible.module_utils.k8s.common import K8sAnsibleMixin, HAS_K8S_MODULE_HELPER
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
-from ansible.module_utils.k8s.inventory import K8sInventoryHelper
+try:
+ from openshift.dynamic.exceptions import DynamicApiError
+except ImportError:
+ pass
+
+
+def format_dynamic_api_exc(exc):
+ if exc.body:
+ if exc.headers and exc.headers.get('Content-Type') == 'application/json':
+ message = json.loads(exc.body).get('message')
+ if message:
+ return message
+ return exc.body
+ else:
+ return '%s Reason: %s' % (exc.status, exc.reason)
+
+
+class K8sInventoryException(Exception):
+ pass
-class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, K8sInventoryHelper):
+
+class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, K8sAnsibleMixin):
NAME = 'k8s'
+ transport = 'kubectl'
+
def parse(self, inventory, loader, path, cache=True):
super(InventoryModule, self).parse(inventory, loader, path)
cache_key = self._get_cache_prefix(path)
config_data = self._read_config_data(path)
self.setup(config_data, cache, cache_key)
+
+ def setup(self, config_data, cache, cache_key):
+ connections = config_data.get('connections')
+
+ if not HAS_K8S_MODULE_HELPER:
+ raise K8sInventoryException(
+ "This module requires the OpenShift Python client. Try `pip install openshift`"
+ )
+
+ source_data = None
+ if cache and cache_key in self._cache:
+ try:
+ source_data = self._cache[cache_key]
+ except KeyError:
+ pass
+
+ if not source_data:
+ self.fetch_objects(connections)
+
+ def fetch_objects(self, connections):
+ client = self.get_api_client()
+
+ if connections:
+ if not isinstance(connections, list):
+ raise K8sInventoryException("Expecting connections to be a list.")
+
+ for connection in connections:
+ if not isinstance(connection, dict):
+ raise K8sInventoryException("Expecting connection to be a dictionary.")
+ client = self.get_api_client(**connection)
+ name = connection.get('name', self.get_default_host_name(client.configuration.host))
+ if connection.get('namespaces'):
+ namespaces = connection['namespaces']
+ else:
+ namespaces = self.get_available_namespaces(client)
+ for namespace in namespaces:
+ self.get_pods_for_namespace(client, name, namespace)
+ self.get_services_for_namespace(client, name, namespace)
+ else:
+ name = self.get_default_host_name(client.configuration.host)
+ namespaces = self.get_available_namespaces(client)
+ for namespace in namespaces:
+ self.get_pods_for_namespace(client, name, namespace)
+ self.get_services_for_namespace(client, name, namespace)
+
+ @staticmethod
+ def get_default_host_name(host):
+ return host.replace('https://', '').replace('http://', '').replace('.', '-').replace(':', '_')
+
+ def get_available_namespaces(self, client):
+ v1_namespace = client.resources.get(api_version='v1', kind='Namespace')
+ try:
+ obj = v1_namespace.get()
+ except DynamicApiError as exc:
+ self.display.debug(exc)
+ raise K8sInventoryException('Error fetching Namespace list: %s' % format_dynamic_api_exc(exc))
+ return [namespace.metadata.name for namespace in obj.items]
+
+ def get_pods_for_namespace(self, client, name, namespace):
+ v1_pod = client.resources.get(api_version='v1', kind='Pod')
+ try:
+ obj = v1_pod.get(namespace=namespace)
+ except DynamicApiError as exc:
+ self.display.debug(exc)
+ raise K8sInventoryException('Error fetching Pod list: %s' % format_dynamic_api_exc(exc))
+
+ namespace_group = 'namespace_{0}'.format(namespace)
+ namespace_pods_group = '{0}_pods'.format(namespace_group)
+
+ self.inventory.add_group(name)
+ self.inventory.add_group(namespace_group)
+ self.inventory.add_child(name, namespace_group)
+ self.inventory.add_group(namespace_pods_group)
+ self.inventory.add_child(namespace_group, namespace_pods_group)
+
+ for pod in obj.items:
+ pod_name = pod.metadata.name
+ pod_groups = []
+ pod_labels = {} if not pod.metadata.labels else pod.metadata.labels
+ pod_annotations = {} if not pod.metadata.annotations else pod.metadata.annotations
+
+ if pod.metadata.labels:
+ pod_labels = pod.metadata.labels
+ # create a group for each label_value
+ for key, value in pod.metadata.labels:
+ group_name = 'label_{0}_{1}'.format(key, value)
+ if group_name not in pod_groups:
+ pod_groups.append(group_name)
+ self.inventory.add_group(group_name)
+
+ for container in pod.status.containerStatuses:
+ # add each pod_container to the namespace group, and to each label_value group
+ container_name = '{0}_{1}'.format(pod.metadata.name, container.name)
+ self.inventory.add_host(container_name)
+ self.inventory.add_child(namespace_pods_group, container_name)
+ if pod_groups:
+ for group in pod_groups:
+ self.inventory.add_child(group, container_name)
+
+ # Add hostvars
+ self.inventory.set_variable(container_name, 'object_type', 'pod')
+ self.inventory.set_variable(container_name, 'labels', pod_labels)
+ self.inventory.set_variable(container_name, 'annotations', pod_annotations)
+ self.inventory.set_variable(container_name, 'cluster_name', pod.metadata.clusterName)
+ self.inventory.set_variable(container_name, 'pod_node_name', pod.spec.nodeName)
+ self.inventory.set_variable(container_name, 'pod_name', pod.spec.name)
+ self.inventory.set_variable(container_name, 'pod_host_ip', pod.status.hostIP)
+ self.inventory.set_variable(container_name, 'pod_phase', pod.status.phase)
+ self.inventory.set_variable(container_name, 'pod_ip', pod.status.podIP)
+ self.inventory.set_variable(container_name, 'pod_self_link', pod.metadata.selfLink)
+ self.inventory.set_variable(container_name, 'pod_resource_version', pod.metadata.resourceVersion)
+ self.inventory.set_variable(container_name, 'pod_uid', pod.metadata.uid)
+ self.inventory.set_variable(container_name, 'container_name', container.image)
+ self.inventory.set_variable(container_name, 'container_image', container.image)
+ if container.state.running:
+ self.inventory.set_variable(container_name, 'container_state', 'Running')
+ if container.state.terminated:
+ self.inventory.set_variable(container_name, 'container_state', 'Terminated')
+ if container.state.waiting:
+ self.inventory.set_variable(container_name, 'container_state', 'Waiting')
+ self.inventory.set_variable(container_name, 'container_ready', container.ready)
+ self.inventory.set_variable(container_name, 'ansible_remote_tmp', '/tmp/')
+ self.inventory.set_variable(container_name, 'ansible_connection', self.transport)
+ self.inventory.set_variable(container_name, 'ansible_{0}_pod'.format(self.transport),
+ pod_name)
+ self.inventory.set_variable(container_name, 'ansible_{0}_container'.format(self.transport),
+ container.name)
+ self.inventory.set_variable(container_name, 'ansible_{0}_namespace'.format(self.transport),
+ namespace)
+
+ def get_services_for_namespace(self, client, name, namespace):
+ v1_service = client.resources.get(api_version='v1', kind='Service')
+ try:
+ obj = v1_service.get(namespace=namespace)
+ except DynamicApiError as exc:
+ self.display.debug(exc)
+ raise K8sInventoryException('Error fetching Service list: %s' % format_dynamic_api_exc(exc))
+
+ namespace_group = 'namespace_{0}'.format(namespace)
+ namespace_services_group = '{0}_services'.format(namespace_group)
+
+ self.inventory.add_group(name)
+ self.inventory.add_group(namespace_group)
+ self.inventory.add_child(name, namespace_group)
+ self.inventory.add_group(namespace_services_group)
+ self.inventory.add_child(namespace_group, namespace_services_group)
+
+ for service in obj.items:
+ service_name = service.metadata.name
+ service_labels = {} if not service.metadata.labels else service.metadata.labels
+ service_annotations = {} if not service.metadata.annotations else service.metadata.annotations
+
+ self.inventory.add_host(service_name)
+
+ if service.metadata.labels:
+ # create a group for each label_value
+ for key, value in service.metadata.labels:
+ group_name = 'label_{0}_{1}'.format(key, value)
+ self.inventory.add_group(group_name)
+ self.inventory.add_child(group_name, service_name)
+
+ try:
+ self.inventory.add_child(namespace_services_group, service_name)
+ except AnsibleError as e:
+ raise
+
+ ports = [{'name': port.name,
+ 'port': port.port,
+ 'protocol': port.protocol,
+ 'targetPort': port.targetPort,
+ 'nodePort': port.nodePort} for port in service.spec.ports or []]
+
+ # add hostvars
+ self.inventory.set_variable(service_name, 'object_type', 'service')
+ self.inventory.set_variable(service_name, 'labels', service_labels)
+ self.inventory.set_variable(service_name, 'annotations', service_annotations)
+ self.inventory.set_variable(service_name, 'cluster_name', service.metadata.clusterName)
+ self.inventory.set_variable(service_name, 'ports', ports)
+ self.inventory.set_variable(service_name, 'type', service.spec.type)
+ self.inventory.set_variable(service_name, 'self_link', service.metadata.selfLink)
+ self.inventory.set_variable(service_name, 'resource_version', service.metadata.resourceVersion)
+ self.inventory.set_variable(service_name, 'uid', service.metadata.uid)
+
+ if service.spec.externalTrafficPolicy:
+ self.inventory.set_variable(service_name, 'external_traffic_policy',
+ service.spec.externalTrafficPolicy)
+ if service.spec.externalIPs:
+ self.inventory.set_variable(service_name, 'external_ips', service.spec.externalIPs)
+
+ if service.spec.externalName:
+ self.inventory.set_variable(service_name, 'external_name', service.spec.externalName)
+
+ if service.spec.healthCheckNodePort:
+ self.inventory.set_variable(service_name, 'health_check_node_port',
+ service.spec.healthCheckNodePort)
+ if service.spec.loadBalancerIP:
+ self.inventory.set_variable(service_name, 'load_balancer_ip',
+ service.spec.loadBalancerIP)
+ if service.spec.selector:
+ self.inventory.set_variable(service_name, 'selector', service.spec.selector)
+
+ if hasattr(service.status.loadBalancer, 'ingress') and service.status.loadBalancer.ingress:
+ load_balancer = [{'hostname': ingress.hostname,
+ 'ip': ingress.ip} for ingress in service.status.loadBalancer.ingress]
+ self.inventory.set_variable(service_name, 'load_balancer', load_balancer)
diff --git a/lib/ansible/plugins/inventory/openshift.py b/lib/ansible/plugins/inventory/openshift.py
index 97e3053f1d..d9e7602ce2 100644
--- a/lib/ansible/plugins/inventory/openshift.py
+++ b/lib/ansible/plugins/inventory/openshift.py
@@ -108,15 +108,85 @@ connections:
context: 'awx/192-168-64-4:8443/developer'
'''
-from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
-from ansible.module_utils.k8s.inventory import OpenShiftInventoryHelper
+from ansible.plugins.inventory.k8s import K8sInventoryException, InventoryModule as K8sInventoryModule, format_dynamic_api_exc
+try:
+ from openshift.dynamic.exceptions import DynamicApiError
+except ImportError:
+ pass
-class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, OpenShiftInventoryHelper):
+
+class InventoryModule(K8sInventoryModule):
NAME = 'openshift'
- def parse(self, inventory, loader, path, cache=True):
- super(InventoryModule, self).parse(inventory, loader, path)
- cache_key = self._get_cache_prefix(path)
- config_data = self._read_config_data(path)
- self.setup(config_data, cache, cache_key)
+ transport = 'oc'
+
+ def fetch_objects(self, connections):
+ super(InventoryModule, self).fetch_objects(connections)
+ client = self.get_api_client()
+
+ if connections:
+ for connection in connections:
+ client = self.get_api_client(**connection)
+ name = connection.get('name', self.get_default_host_name(client.configuration.host))
+ if connection.get('namespaces'):
+ namespaces = connection['namespaces']
+ else:
+ namespaces = self.get_available_namespaces(client)
+ for namespace in namespaces:
+ self.get_routes_for_namespace(client, name, namespace)
+ else:
+ name = self.get_default_host_name(client.configuration.host)
+ namespaces = self.get_available_namespaces(client)
+ for namespace in namespaces:
+ self.get_routes_for_namespace(client, name, namespace)
+
+ def get_routes_for_namespace(self, client, name, namespace):
+ v1_route = client.resources.get(api_version='v1', kind='Route')
+ try:
+ obj = v1_route.get(namespace=namespace)
+ except DynamicApiError as exc:
+ self.display.debug(exc)
+ raise K8sInventoryException('Error fetching Routes list: %s' % format_dynamic_api_exc(exc))
+
+ namespace_group = 'namespace_{0}'.format(namespace)
+ namespace_routes_group = '{0}_routes'.format(namespace_group)
+
+ self.inventory.add_group(name)
+ self.inventory.add_group(namespace_group)
+ self.inventory.add_child(name, namespace_group)
+ self.inventory.add_group(namespace_routes_group)
+ self.inventory.add_child(namespace_group, namespace_routes_group)
+ for route in obj.items:
+ route_name = route.metadata.name
+ route_labels = {} if not route.metadata.labels else route.metadata.labels
+ route_annotations = {} if not route.metadata.annotations else route.metadata.annotations
+
+ self.inventory.add_host(route_name)
+
+ if route.metadata.labels:
+ # create a group for each label_value
+ for key, value in route.metadata.labels:
+ group_name = 'label_{0}_{1}'.format(key, value)
+ self.inventory.add_group(group_name)
+ self.inventory.add_child(group_name, route_name)
+
+ self.inventory.add_child(namespace_routes_group, route_name)
+
+ # add hostvars
+ self.inventory.set_variable(route_name, 'labels', route_labels)
+ self.inventory.set_variable(route_name, 'annotations', route_annotations)
+ self.inventory.set_variable(route_name, 'cluster_name', route.metadata.clusterName)
+ self.inventory.set_variable(route_name, 'object_type', 'route')
+ self.inventory.set_variable(route_name, 'self_link', route.metadata.selfLink)
+ self.inventory.set_variable(route_name, 'resource_version', route.metadata.resourceVersion)
+ self.inventory.set_variable(route_name, 'uid', route.metadata.uid)
+
+ if route.spec.host:
+ self.inventory.set_variable(route_name, 'host', route.spec.host)
+
+ if route.spec.path:
+ self.inventory.set_variable(route_name, 'path', route.spec.path)
+
+ if hasattr(route.spec.port, 'targetPort') and route.spec.port.targetPort:
+ self.inventory.set_variable(route_name, 'port', route.spec.port)