From 895c5125961cfe5609dbdeaa61fcc9e692ca30a7 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Fri, 22 Jun 2018 08:24:52 +1000 Subject: [PATCH] New k8s_facts module Strip out the facts parts of the k8s module into a new simpler module that deals with querying for facts, also allowing field and label selectors --- lib/ansible/module_utils/k8s/common.py | 11 ++ lib/ansible/modules/clustering/k8s/k8s.py | 16 +- .../modules/clustering/k8s/k8s_facts.py | 171 ++++++++++++++++++ 3 files changed, 183 insertions(+), 15 deletions(-) create mode 100644 lib/ansible/modules/clustering/k8s/k8s_facts.py diff --git a/lib/ansible/module_utils/k8s/common.py b/lib/ansible/module_utils/k8s/common.py index 0cbba3f69f..32e2e6e3a6 100644 --- a/lib/ansible/module_utils/k8s/common.py +++ b/lib/ansible/module_utils/k8s/common.py @@ -189,6 +189,17 @@ class K8sAnsibleMixin(object): if fail: self.fail(msg='Failed to find exact match for {0}.{1} by [kind, name, singularName, shortNames]'.format(api_version, kind)) + def kubernetes_facts(self, kind, api_version, name=None, namespace=None, label_selectors=None, field_selectors=None): + resource = self.find_resource(kind, api_version) + result = resource.get(name=name, + namespace=namespace, + label_selector=','.join(label_selectors), + field_selector=','.join(field_selectors)).to_dict() + if 'items' in result: + return result + else: + return dict(items=[result]) + def remove_aliases(self): """ The helper doesn't know what to do with aliased keys diff --git a/lib/ansible/modules/clustering/k8s/k8s.py b/lib/ansible/modules/clustering/k8s/k8s.py index ab610de938..af265201ab 100644 --- a/lib/ansible/modules/clustering/k8s/k8s.py +++ b/lib/ansible/modules/clustering/k8s/k8s.py @@ -30,6 +30,7 @@ description: - Pass the object definition from a source file or inline. See examples for reading files and using Jinja templates. - Access to the full range of K8s APIs. + - Use the M(k8s_facts) module to obtain a list of items about an object of type C(kind) - Authenticate using either a config file, certificates, password or token. - Supports check mode. @@ -80,21 +81,6 @@ EXAMPLES = ''' state: present src: /testing/service.yml -- name: Get an existing Service object - k8s: - api_version: v1 - kind: Service - name: web - namespace: testing - register: web_service - -- name: Get a list of all service objects - k8s: - api_version: v1 - kind: ServiceList - namespace: testing - register: service_list - - name: Remove an existing Service object k8s: state: absent diff --git a/lib/ansible/modules/clustering/k8s/k8s_facts.py b/lib/ansible/modules/clustering/k8s/k8s_facts.py new file mode 100644 index 0000000000..486096f746 --- /dev/null +++ b/lib/ansible/modules/clustering/k8s/k8s_facts.py @@ -0,0 +1,171 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2018, Will Thames <@willthames> +# 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 + + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = ''' +module: k8s_facts + +short_description: Describe Kubernetes (K8s) objects + +version_added: "2.7" + +author: + - "Will Thames (@willthames)" + +description: + - Use the OpenShift Python client to perform read operations on K8s objects. + - Access to the full range of K8s APIs. + - Authenticate using either a config file, certificates, password or token. + - Supports check mode. + +options: + api_version: + description: + - Use to specify the API version. in conjunction with I(kind), I(name), and I(namespace) to identify a + specific object. + default: v1 + aliases: + - api + - version + kind: + description: + - Use to specify an object model. Use in conjunction with I(api_version), I(name), and I(namespace) to identify a + specific object. + required: yes + name: + description: + - Use to specify an object name. Use in conjunction with I(api_version), I(kind) and I(namespace) to identify a + specific object. + namespace: + description: + - Use to specify an object namespace. Use in conjunction with I(api_version), I(kind), and I(name) + to identify a specfic object. + label_selectors: + description: List of label selectors to use to filter results + field_selectors: + description: List of field selectors to use to filter results + +extends_documentation_fragment: + - k8s_auth_options + +requirements: + - "python >= 2.7" + - "openshift >= 0.6" + - "PyYAML >= 3.11" +''' + +EXAMPLES = ''' +- name: Get an existing Service object + k8s_facts: + api_version: v1 + kind: Service + name: web + namespace: testing + register: web_service + +- name: Get a list of all service objects + k8s_facts: + api_version: v1 + kind: Service + namespace: testing + register: service_list + +- name: Get a list of all pods from any namespace + k8s_facts: + kind: Pod + register: pod_list + +- name: Search for all Pods labelled app=web + k8s_facts: + kind: Pod + label_selectors: + - app = web + - tier in (dev, test) + +- name: Search for all running pods + k8s_facts: + kind: Pod + field_selectors: + - status.phase = running +''' + +RETURN = ''' +items: + description: + - The object(s) that exists + returned: success + 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: dict + spec: + description: Specific attributes of the object. Will vary based on the I(api_version) and I(kind). + returned: success + type: dict + status: + description: Current status details for the object. + returned: success + type: dict +''' + + +from ansible.module_utils.k8s.common import KubernetesAnsibleModule, AUTH_ARG_SPEC +import copy + + +class KubernetesFactsModule(KubernetesAnsibleModule): + + def execute_module(self): + self.client = self.get_api_client() + + self.exit_json(changed=False, + **self.kubernetes_facts(self.params['kind'], + self.params['api_version'], + self.params['name'], + self.params['namespace'], + self.params['label_selectors'], + self.params['field_selectors'])) + + @property + def argspec(self): + args = copy.deepcopy(AUTH_ARG_SPEC) + args.update( + dict( + kind=dict(required=True), + api_version=dict(default='v1', aliases=['api', 'version']), + name=dict(), + namespace=dict(), + label_selectors=dict(type='list', default=[]), + field_selectors=dict(type='list', default=[]), + ) + ) + return args + + +def main(): + KubernetesFactsModule().execute_module() + + +if __name__ == '__main__': + main()