diff --git a/lib/ansible/module_utils/k8s/common.py b/lib/ansible/module_utils/k8s/common.py
index 45f9fc947a0..369b221de32 100644
--- a/lib/ansible/module_utils/k8s/common.py
+++ b/lib/ansible/module_utils/k8s/common.py
@@ -70,6 +70,20 @@ def remove_secret_data(obj_dict):
obj_dict['metadata']['annotations'].pop(key)
+def to_snake(name):
+ """ Convert a string from camel to snake """
+ if not name:
+ return name
+
+ def _replace(m):
+ m = m.group(0)
+ return m[0] + '_' + m[1:]
+
+ p = r'[a-z][A-Z]|' \
+ r'[A-Z]{2}[a-z]'
+ return re.sub(p, _replace, name).lower()
+
+
class DateTimeEncoder(json.JSONEncoder):
# When using json.dumps() with K8s object, pass cls=DateTimeEncoder to handle any datetime objects
def default(self, o):
@@ -122,7 +136,7 @@ class KubernetesAnsibleModule(AnsibleModule):
self.kind = self.resource_definition.get('kind')
self.api_version = self.api_version.lower()
- self.kind = self._to_snake(self.kind)
+ self.kind = to_snake(self.kind)
if not self.api_version:
self.fail_json(
@@ -320,7 +334,7 @@ class KubernetesAnsibleModule(AnsibleModule):
def _add_parameter(self, request, path, parameters):
for key, value in iteritems(request):
if path:
- param_name = '_'.join(path + [self._to_snake(key)])
+ param_name = '_'.join(path + [to_snake(key)])
else:
param_name = self.helper.attribute_to_snake(key)
if param_name in self.helper.argspec and value is not None:
@@ -335,25 +349,6 @@ class KubernetesAnsibleModule(AnsibleModule):
"expected by the OpenShift Python module.".format(param_name))
)
- @staticmethod
- def _to_snake(name):
- """
- Convert a string from camel to snake
- :param name: string to convert
- :return: string
- """
- if not name:
- return name
-
- def replace(m):
- m = m.group(0)
- return m[0] + '_' + m[1:]
-
- p = r'[a-z][A-Z]|' \
- r'[A-Z]{2}[a-z]'
- result = re.sub(p, replace, name)
- return result.lower()
-
class OpenShiftAnsibleModuleHelper(AnsibleMixin, OpenShiftObjectHelper):
pass
diff --git a/lib/ansible/module_utils/k8s/lookup.py b/lib/ansible/module_utils/k8s/lookup.py
new file mode 100644
index 00000000000..6058f593097
--- /dev/null
+++ b/lib/ansible/module_utils/k8s/lookup.py
@@ -0,0 +1,219 @@
+#
+# 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 .
+
+from __future__ import absolute_import, division, print_function
+
+import json
+import os
+
+from ansible.module_utils.k8s.common import DateTimeEncoder, remove_secret_data, to_snake
+from ansible.module_utils.k8s.helper import AUTH_ARG_SPEC
+
+try:
+ from openshift.helper.kubernetes import KubernetesObjectHelper
+ from openshift.helper.openshift import OpenShiftObjectHelper
+ from openshift.helper.exceptions import KubernetesException
+ HAS_K8S_MODULE_HELPER = True
+except ImportError as exc:
+ HAS_K8S_MODULE_HELPER = False
+
+try:
+ import yaml
+ HAS_YAML = True
+except ImportError:
+ HAS_YAML = False
+
+
+class KubernetesLookup(object):
+
+ def __init__(self):
+
+ if not HAS_K8S_MODULE_HELPER:
+ raise Exception(
+ "Requires the OpenShift Python client. Try `pip install openshift`"
+ )
+
+ if not HAS_YAML:
+ raise Exception(
+ "Requires PyYAML. Try `pip install PyYAML`"
+ )
+
+ self.kind = None
+ self.name = None
+ self.namespace = None
+ self.api_version = None
+ self.label_selector = None
+ self.field_selector = None
+ self.include_uninitialized = None
+ self.resource_definition = None
+ self.helper = None
+ self.connection = {}
+
+ def run(self, terms, variables=None, **kwargs):
+ self.mylog('Here!')
+ self.kind = kwargs.get('kind')
+ self.name = kwargs.get('resource_name')
+ self.namespace = kwargs.get('namespace')
+ self.api_version = kwargs.get('api_version', 'v1')
+ self.label_selector = kwargs.get('label_selector')
+ self.field_selector = kwargs.get('field_selector')
+ self.include_uninitialized = kwargs.get('include_uninitialized', False)
+
+ resource_definition = kwargs.get('resource_definition')
+ src = kwargs.get('src')
+ if src:
+ resource_definition = self.load_resource_definition(src)
+ if resource_definition:
+ self.params_from_resource_definition(resource_definition)
+
+ if not self.kind:
+ raise Exception(
+ "Error: no Kind specified. Use the 'kind' parameter, or provide an object YAML configuration "
+ "using the 'resource_definition' parameter."
+ )
+
+ self.kind = to_snake(self.kind)
+ self.helper = self.get_helper()
+
+ for arg in AUTH_ARG_SPEC:
+ self.connection[arg] = kwargs.get(arg)
+
+ try:
+ self.helper.set_client_config(**self.connection)
+ except Exception as exc:
+ raise Exception(
+ "Client authentication failed: {0}".format(exc.message)
+ )
+
+ if self.name:
+ self.mylog("Calling get_object()")
+ return self.get_object()
+
+ return self.list_objects()
+
+ def mylog(self, msg):
+ with open('loggit.txt', 'a') as f:
+ f.write(msg + '\n')
+
+ def get_helper(self):
+ try:
+ helper = KubernetesObjectHelper(api_version=self.api_version, kind=self.kind, debug=False)
+ helper.get_model(self.api_version, self.kind)
+ return helper
+ except KubernetesException as exc:
+ raise Exception("Error initializing helper: {0}".format(exc.message))
+
+ def load_resource_definition(self, src):
+ """ Load the requested src path """
+ path = os.path.normpath(src)
+ if not os.path.exists(path):
+ raise Exception("Error accessing {0}. Does the file exist?".format(path))
+ try:
+ result = yaml.safe_load(open(path, 'r'))
+ except (IOError, yaml.YAMLError) as exc:
+ raise Exception("Error loading resource_definition: {0}".format(exc))
+ return result
+
+ def params_from_resource_definition(self, defn):
+ if defn.get('apiVersion'):
+ self.api_version = defn['apiVersion']
+ if defn.get('kind'):
+ self.kind = defn['kind']
+ if defn.get('metadata', {}).get('name'):
+ self.name = defn['metadata']['name']
+ if defn.get('metadata', {}).get('namespace'):
+ self.namespace = defn['metadata']['namespace']
+
+ def get_object(self):
+ """ Fetch a named object """
+ try:
+ result = self.helper.get_object(self.name, self.namespace)
+ except KubernetesException as exc:
+ raise Exception('Failed to retrieve requested object: {0}'.format(exc.message))
+ self.mylog("Got restult")
+ response = []
+ if result is not None:
+ # Convert Datetime objects to ISO format
+ result_json = json.loads(json.dumps(result.to_dict(), cls=DateTimeEncoder))
+ if self.kind == 'secret':
+ remove_secret_data(result_json)
+ response.append(result_json)
+
+ return response
+
+ def list_objects(self):
+ """ Query for a set of objects """
+ if self.namespace:
+ method_name = 'list_namespaced_{0}'.format(self.kind)
+ try:
+ method = self.helper.lookup_method(method_name=method_name)
+ except KubernetesException:
+ raise Exception(
+ "Failed to find method {0} for API {1}".format(method_name, self.api_version)
+ )
+ else:
+ method_name = 'list_{0}_for_all_namespaces'.format(self.kind)
+ try:
+ method = self.helper.lookup_method(method_name=method_name)
+ except KubernetesException:
+ method_name = 'list_{0}'.format(self.kind)
+ try:
+ method = self.helper.lookup_method(method_name=method_name)
+ except KubernetesException:
+ raise Exception(
+ "Failed to find method for API {0} and Kind {1}".format(self.api_version, self.kind)
+ )
+
+ params = {}
+ if self.field_selector:
+ params['field_selector'] = self.field_selector
+ if self.label_selector:
+ params['label_selector'] = self.label_selector
+ params['include_uninitialized'] = self.include_uninitialized
+
+ if self.namespace:
+ try:
+ result = method(self.namespace, **params)
+ except KubernetesException as exc:
+ raise Exception(exc.message)
+ else:
+ try:
+ result = method(**params)
+ except KubernetesException as exc:
+ raise Exception(exc.message)
+
+ response = []
+ if result is not None:
+ # Convert Datetime objects to ISO format
+ result_json = json.loads(json.dumps(result.to_dict(), cls=DateTimeEncoder))
+ response = result_json.get('items', [])
+ if self.kind == 'secret':
+ for item in response:
+ remove_secret_data(item)
+ return response
+
+
+class OpenShiftLookup(KubernetesLookup):
+
+ def get_helper(self):
+ try:
+ helper = OpenShiftObjectHelper(api_version=self.api_version, kind=self.kind, debug=False)
+ helper.get_model(self.api_version, self.kind)
+ return helper
+ except KubernetesException as exc:
+ raise Exception("Error initializing helper: {0}".format(exc.message))
diff --git a/lib/ansible/plugins/lookup/k8s.py b/lib/ansible/plugins/lookup/k8s.py
new file mode 100644
index 00000000000..d567332347c
--- /dev/null
+++ b/lib/ansible/plugins/lookup/k8s.py
@@ -0,0 +1,198 @@
+#
+# 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 .
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+ lookup: k8s
+
+ version_added: "2.5"
+
+ short_description: Query the K8s API
+
+ description:
+ - Uses the OpenShift Python client to fetch a specific object by name, all matching objects within a
+ namespace, or all matching objects for all namespaces.
+ - Provides access the full range of K8s APIs.
+ - Enables authentication via config file, certificates, password or token.
+
+ options:
+ api_version:
+ description:
+ - Use to specify the API version. If I(resource definition) is provided, the I(apiVersion) from the
+ I(resource_definition) will override this option.
+ default: v1
+ kind:
+ description:
+ - Use to specify an object model. If I(resource definition) is provided, the I(kind) from a
+ I(resource_definition) will override this option.
+ required: true
+ name:
+ description:
+ - Fetch a specific object by name. If I(resource definition) is provided, the I(metadata.name) value
+ from the I(resource_definition) will override this option.
+ namespace:
+ description:
+ - Limit the objects returned to a specific namespace. If I(resource definition) is provided, the
+ I(metadata.namespace) value from the I(resource_definition) will override this option.
+ label_selector:
+ description:
+ - Additional labels to include in the query. Ignored when I(resource_name) is provided.
+ field_selector:
+ description:
+ - Specific fields on which to query. Ignored when I(resource_name) is provided.
+ resource_definition:
+ description:
+ - "Provide a YAML configuration for an object. NOTE: I(kind), I(api_version), I(resource_name),
+ and I(namespace) will be overwritten by corresponding values found in the provided I(resource_definition)."
+ src:
+ description:
+ - "Provide a path to a file containing a valid YAML definition of an object dated. Mutually
+ exclusive with I(resource_definition). NOTE: I(kind), I(api_version), I(resource_name), and I(namespace)
+ will be overwritten by corresponding values found in the configuration read in from the I(src) file."
+ - Reads from the local file system. To read from the Ansible controller's file system, use the file lookup
+ plugin or template lookup plugin, combined with the from_yaml filter, and pass the result to
+ I(resource_definition). See Examples below.
+ host:
+ description:
+ - Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable.
+ api_key:
+ description:
+ - Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment variable.
+ kubeconfig:
+ description:
+ - Path to an existing Kubernetes config file. If not provided, and no other connection
+ options are provided, the openshift client will attempt to load the default
+ configuration file from I(~/.kube/config.json). Can also be specified via K8S_AUTH_KUBECONFIG environment
+ variable.
+ context:
+ description:
+ - The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment
+ variable.
+ username:
+ description:
+ - Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME environment
+ variable.
+ password:
+ description:
+ - Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD environment
+ variable.
+ cert_file:
+ description:
+ - Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE
+ environment
+ variable.
+ key_file:
+ description:
+ - Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_HOST environment
+ variable.
+ ssl_ca_cert:
+ description:
+ - Path to a CA certificate used to authenticate with the API. Can also be specified via K8S_AUTH_SSL_CA_CERT
+ environment variable.
+ verify_ssl:
+ description:
+ - Whether or not to verify the API server's SSL certificates. Can also be specified via K8S_AUTH_VERIFY_SSL
+ environment variable.
+ type: bool
+
+ requirements:
+ - "python >= 2.7"
+ - "openshift >= 0.3"
+ - "PyYAML >= 3.11"
+
+ notes:
+ - "The OpenShift Python client wraps the K8s Python client, providing full access to
+ all of the APIS and models available on both platforms. For API version details and
+ additional information visit https://github.com/openshift/openshift-restclient-python"
+"""
+
+EXAMPLES = """
+- name: Fetch a list of namespaces
+ set_fact:
+ projects: "{{ lookup('k8s', api_version='v1', kind='Namespace') }}"
+
+- name: Fetch all deployments
+ set_fact:
+ deployments: "{{ lookup('k8s', kind='Deployment', namespace='testing') }}"
+
+- name: Fetch all deployments in a namespace
+ set_fact:
+ deployments: "{{ lookup('k8s', kind='Deployment', namespace='testing') }}"
+
+- name: Fetch a specific deployment by name
+ set_fact:
+ deployments: "{{ lookup('k8s', kind='Deployment', namespace='testing', resource_name='elastic') }}"
+
+- name: Fetch with label selector
+ set_fact:
+ service: "{{ lookup('k8s', kind='Service', label_selector='app=galaxy') }}"
+
+# Use parameters from a YAML config
+
+- name: Load config from the Ansible controller filesystem
+ set_fact:
+ config: "{{ lookup('file', 'service.yml') | from_yaml }}"
+
+- name: Using the config (loaded from a file in prior task), fetch the latest version of the object
+ set_fact:
+ service: "{{ lookup('k8s', resource_definition=config) }}"
+
+- name: Use a config from the local filesystem
+ set_fact:
+ service: "{{ lookup('k8s', src='service.yml') }}"
+"""
+
+RETURN = """
+ _list:
+ description:
+ - One ore more object definitions returned from the API.
+ type: complex
+ contains:
+ api_version:
+ description: The versioned schema of this representation of an object.
+ returned: success
+ type: str
+ kind:
+ description: Represents the REST resource this object represents.
+ returned: success
+ type: str
+ metadata:
+ description: Standard object metadata. Includes name, namespace, annotations, labels, etc.
+ returned: success
+ type: complex
+ spec:
+ description: Specific attributes of the object. Will vary based on the I(api_version) and I(kind).
+ returned: success
+ type: complex
+ status:
+ description: Current status details for the object.
+ returned: success
+ type: complex
+"""
+
+from ansible.plugins.lookup import LookupBase
+from ansible.module_utils.k8s.lookup import KubernetesLookup
+
+
+class LookupModule(LookupBase):
+
+ def run(self, terms, variables=None, **kwargs):
+ return KubernetesLookup().run(terms, variables=variables, **kwargs)
diff --git a/lib/ansible/plugins/lookup/openshift.py b/lib/ansible/plugins/lookup/openshift.py
index 6753141971b..5c12e747a81 100644
--- a/lib/ansible/plugins/lookup/openshift.py
+++ b/lib/ansible/plugins/lookup/openshift.py
@@ -1,248 +1,197 @@
-# -*- coding: utf-8 -*-
-# (c) 2017, Kenneth D. Evensen
-
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# 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 .
from __future__ import (absolute_import, division, print_function)
+
__metaclass__ = type
DOCUMENTATION = """
lookup: openshift
+
version_added: "2.5"
- short_description: Returns the JSON definition of an object in OpenShift
+
+ short_description: Query the OpenShift API
+
description:
- - This lookup plugin provides the ability to query an OpenShift Container
- - platform cluster for information about objects. This plugin requires
- - a valid user or service account token.
+ - Uses the OpenShift Python client to fetch a specific object by name, all matching objects within a
+ namespace, or all matching objects for all namespaces.
+ - Provides access the full range of K8s APIs.
+ - Enables authentication via config file, certificates, password or token.
+
options:
+ api_version:
+ description:
+ - Use to specify the API version. If I(resource definition) is provided, the I(apiVersion) from the
+ I(resource_definition) will override this option.
+ default: v1
kind:
description:
- - The kind of OpenShift resource to read (e.g. Project, Service, Pod)
- required: True
- host:
- description:
- - The IP address of the host serving the OpenShift API
- required: False
- default: 127.0.0.1
- port:
- description:
- - The port on which to access the OpenShift API
- required: False
- default: 8443
- token:
- description:
- - The token to use for authentication against the OpenShift API.
- - This can be a user or ServiceAccount token.
- required: True
- validate_certs:
- description:
- - Whether or not to validate the TLS certificate of the API.
- required: False
- default: True
- namespace:
- description:
- - The namespace/project where the object resides.
- required: False
+ - Use to specify an object model. If I(resource definition) is provided, the I(kind) from a
+ I(resource_definition) will override this option.
+ required: true
resource_name:
description:
- - The name of the object to query.
- required: False
- pretty:
+ - Fetch a specific object by name. If I(resource definition) is provided, the I(metadata.name) value
+ from the I(resource_definition) will override this option.
+ namespace:
description:
- - Whether or not to prettify the output. This is useful for debugging.
- required: False
- default: False
- labelSelector:
+ - Limit the objects returned to a specific namespace. If I(resource definition) is provided, the
+ I(metadata.namespace) value from the I(resource_definition) will override this option.
+ label_selector:
description:
- - Additional labels to include in the query.
- required: False
- fieldSelector:
+ - Additional labels to include in the query. Ignored when I(resource_name) is provided.
+ field_selector:
description:
- - Specific fields on which to query.
- required: False
- resourceVersion:
+ - Specific fields on which to query. Ignored when I(resource_name) is provided.
+ resource_definition:
description:
- - Query for a specific resource version.
- required: False
+ - "Provide a YAML configuration for an object. NOTE: I(kind), I(api_version), I(resource_name), I(namespace),
+ and I(resource_version) will be overwritten by corresponding values found in the provided
+ I(resource_definition)."
+ src:
+ description:
+ - "Provide a path to a file containing a valid YAML definition of an object dated. Mutually
+ exclusive with I(resource_definition). NOTE: I(kind), I(api_version), I(resource_name), and I(namespace)
+ will be overwritten by corresponding values found in the configuration read in from the I(src) file."
+ - Reads from the local file system. To read from the Ansible controller's file system, use the file lookup
+ plugin or template lookup plugin, combined with the from_yaml filter, and pass the result to
+ I(resource_definition). See Examples below.
+ host:
+ description:
+ - Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable.
+ api_key:
+ description:
+ - Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment variable.
+ kubeconfig:
+ description:
+ - Path to an existing Kubernetes config file. If not provided, and no other connection
+ options are provided, the openshift client will attempt to load the default
+ configuration file from I(~/.kube/config.json). Can also be specified via K8S_AUTH_KUBECONFIG environment
+ variable.
+ context:
+ description:
+ - The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment
+ variable.
+ username:
+ description:
+ - Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME environment
+ variable.
+ password:
+ description:
+ - Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD environment
+ variable.
+ cert_file:
+ description:
+ - Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE
+ environment variable.
+ key_file:
+ description:
+ - Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_HOST environment
+ variable.
+ ssl_ca_cert:
+ description:
+ - Path to a CA certificate used to authenticate with the API. Can also be specified via K8S_AUTH_SSL_CA_CERT
+ environment variable.
+ verify_ssl:
+ description:
+ - Whether or not to verify the API server's SSL certificates. Can also be specified via K8S_AUTH_VERIFY_SSL
+ environment variable.
+ type: bool
+
+ requirements:
+ - "python >= 2.7"
+ - "openshift >= 0.3"
+ - "PyYAML >= 3.11"
+
+ notes:
+ - "The OpenShift Python client wraps the K8s Python client, providing full access to
+ all of the APIS and models available on both platforms. For API version details and
+ additional information visit https://github.com/openshift/openshift-restclient-python"
"""
EXAMPLES = """
-- name: Get Project {{ project_name }}
+- name: Fetch a list of projects
set_fact:
- project_fact: "{{ lookup('openshift',
- kind='Project',
- host=inventory_host,
- token=hostvars[inventory_host]['ansible_sa_token'],
- resource_name=project_name,
- validate_certs=validate_certs) }}"
-- name: Get All Service Accounts in a Project
+ projects: "{{ lookup('openshift', api_version='v1', kind='Project') }}"
+
+- name: Fetch all deployments
set_fact:
- service_fact: "{{ lookup('openshift',
- kind='ServiceAccount',
- host=inventory_host,
- token=hostvars[inventory_host]['ansible_sa_token'],
- namespace=project_name,
- validate_certs=validate_certs) }}"
+ deployments: "{{ lookup('openshift', kind='DeploymentConfig', namespace='testing') }}"
+
+- name: Fetch all deployments in a namespace
+ set_fact:
+ deployments: "{{ lookup('openshift', kind='DeploymentConfig', namespace='testing') }}"
+
+- name: Fetch a specific deployment by name
+ set_fact:
+ deployments: "{{ lookup('openshift', kind='DeploymentConfig', namespace='testing', resource_name='elastic') }}"
+
+- name: Fetch with label selector
+ set_fact:
+ service: "{{ lookup('openshift', kind='Service', label_selector='app=galaxy') }}"
+
+# Use parameters from a YAML config
+
+- name: Load config from the Ansible controller filesystem
+ set_fact:
+ config: "{{ lookup('file', 'service.yml') | from_yaml }}"
+
+- name: Using the config (loaded from a file in prior task), fetch the latest version of the object
+ set_fact:
+ service: "{{ lookup('openshift', resource_definition=config) }}"
+
+- name: Use a config from the local filesystem
+ set_fact:
+ service: "{{ lookup('openshift', src='service.yml') }}"
"""
RETURN = """
_list:
description:
- - An object definition or list of objects definitions returned from OpenShift.
- type: dict
+ - One or more object definitions returned from the API.
+ type: complex
+ contains:
+ api_version:
+ description: The versioned schema of this representation of an object.
+ returned: success
+ type: str
+ kind:
+ description: Represents the REST resource this object represents.
+ returned: success
+ type: str
+ metadata:
+ description: Standard object metadata. Includes name, namespace, annotations, labels, etc.
+ returned: success
+ type: complex
+ spec:
+ description: Specific attributes of the object. Will vary based on the I(api_version) and I(kind).
+ returned: success
+ type: complex
+ status:
+ description: Current status details for the object.
+ returned: success
+ type: complex
"""
-import json
-from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
-from ansible.module_utils import urls
-from ansible.module_utils.six.moves import urllib
-from ansible.module_utils.six.moves import urllib_error
-from ansible.module_utils.six.moves.urllib.parse import urlencode
-from ansible.module_utils._text import to_text
-from ansible.module_utils._text import to_native
-
-
-class OcpQuery(object):
- def __init__(self, host, port, token, validate_certs):
- self.apis = ['api', 'oapi']
- self.token = token
- self.validate_certs = validate_certs
- self.host = host
- self.port = port
- self.kinds = {}
- bearer = "Bearer " + self.token
- self.headers = {"Authorization": bearer}
- self.build_facts()
-
- def build_facts(self):
-
- for api in self.apis:
- url = "https://{0}:{1}/{2}/v1".format(self.host, self.port, api)
- try:
- response = urls.open_url(url=url,
- headers=self.headers,
- validate_certs=self.validate_certs,
- method='get')
- except urllib_error.HTTPError as error:
- try:
- body = to_native(error.read())
- except AttributeError:
- body = ''
- raise AnsibleError("OC Query raised exception with code {0} and message {1} against url {2}".format(error.code, body, url))
-
- for resource in json.loads(to_text(response.read(), errors='surrogate_or_strict'))['resources']:
- if 'generated' not in resource['name']:
- self.kinds[resource['kind']] = \
- {'kind': resource['kind'],
- 'name': resource['name'].split('/')[0],
- 'namespaced': resource['namespaced'],
- 'api': api,
- 'version': 'v1',
- 'baseurl': url
- }
-
- def url(self, kind=None, namespace=None, resource_name=None, pretty=False, labelSelector=None, fieldSelector=None, resourceVersion=None):
- first_param = True
-
- url = [self.kinds[kind]['baseurl']]
- if self.kinds[kind]['namespaced'] is True:
- url.append('/namespaces/')
- if namespace is None:
- raise AnsibleError('Kind %s requires a namespace.'
- ' None provided' % kind)
- url.append(namespace)
-
- url.append('/' + self.kinds[kind]['name'])
-
- if resource_name is not None:
- url.append('/' + resource_name)
-
- if pretty:
- url.append('?pretty')
- first_param = False
-
- if labelSelector is not None:
- if first_param:
- url.append('?')
- else:
- url.append('&')
-
- url.append(urlencode({'labelSelector': labelSelector}))
- first_param = False
-
- if fieldSelector is not None:
- if first_param:
- url.append('?')
- else:
- url.append('&')
-
- url.append(urlencode({'fieldSelector': fieldSelector}))
- first_param = False
-
- if resourceVersion is not None:
- if first_param:
- url.append('?')
- else:
- url.append('&')
-
- url.append(urlencode({'resourceVersion': resourceVersion}))
- first_param = False
-
- return "".join(url)
-
- def query(self, kind=None, namespace=None, resource_name=None, pretty=False, labelSelector=None, fieldSelector=None, resourceVersion=None):
- url = self.url(kind=kind,
- namespace=namespace,
- resource_name=resource_name,
- pretty=pretty,
- labelSelector=labelSelector,
- fieldSelector=fieldSelector,
- resourceVersion=resourceVersion)
-
- try:
- response = urls.open_url(url=url,
- headers=self.headers,
- validate_certs=self.validate_certs,
- method='get')
- except urllib_error.HTTPError as error:
- try:
- body = to_native(error.read())
- except AttributeError:
- body = ''
- raise AnsibleError("OC Query raised exception with code {0} and message {1} against url {2}".format(error.code, body, url))
-
- return json.loads(to_text(response.read(), errors='surrogate_or_strict'))
+from ansible.module_utils.k8s.lookup import OpenShiftLookup
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
-
- host = kwargs.get('host', '127.0.0.1')
- port = kwargs.get('port', '8443')
- validate_certs = kwargs.get('validate_certs', True)
- token = kwargs.get('token', None)
-
- namespace = kwargs.get('namespace', None)
- resource_name = kwargs.get('resource_name', None)
- pretty = kwargs.get('pretty', False)
- label_selector = kwargs.get('labelSelector', None)
- field_selector = kwargs.get('fieldSelector', None)
- resource_version = kwargs.get('resourceVersion', None)
- resource_kind = kwargs.get('kind', None)
-
- ocp = OcpQuery(host, port, token, validate_certs)
-
- search_response = ocp.query(kind=resource_kind,
- namespace=namespace,
- resource_name=resource_name,
- pretty=pretty,
- labelSelector=label_selector,
- fieldSelector=field_selector,
- resourceVersion=resource_version)
- if search_response is not None and "items" in search_response:
- search_response['item_list'] = search_response.pop('items')
-
- values = [search_response]
-
- return values
+ return OpenShiftLookup().run(terms, variables=variables, **kwargs)