From 5de49373b73b10f0edd2eb3ccec079af5e773380 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 28 Sep 2020 14:01:37 +0530 Subject: [PATCH] k8s_cluster_info: new module (#160) Get information about k8s APIs Signed-off-by: Abhijeet Kasurde --- README.md | 1 + molecule/default/converge.yml | 3 +- molecule/default/tasks/cluster_info.yml | 22 +++ plugins/modules/k8s_cluster_info.py | 247 ++++++++++++++++++++++++ 4 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 molecule/default/tasks/cluster_info.yml create mode 100644 plugins/modules/k8s_cluster_info.py diff --git a/README.md b/README.md index e3d7c6b9..8546fdb7 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Click on the name of a plugin or module to view that content's documentation: - **Modules**: - [k8s](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_module.html) - [k8s_auth](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_auth_module.html) + - [k8s_cluster_info](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/k8s_cluster_info.py) - [k8s_exec](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_exec_module.html) - [k8s_info](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_info_module.html) - [k8s_log](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_log_module.html) diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index ab9ce8c2..e3e0aa8d 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -27,8 +27,7 @@ - include_tasks: tasks/full.yml - include_tasks: tasks/exec.yml - include_tasks: tasks/log.yml - - include_tasks: tasks/info.yml - - include_tasks: tasks/template.yml + - include_tasks: tasks/cluster_info.yml roles: - helm diff --git a/molecule/default/tasks/cluster_info.yml b/molecule/default/tasks/cluster_info.yml new file mode 100644 index 00000000..644de153 --- /dev/null +++ b/molecule/default/tasks/cluster_info.yml @@ -0,0 +1,22 @@ +--- +- name: Get Information about All APIs + k8s_cluster_info: + register: api_details + +- name: Print all APIs for debugging + debug: + msg: "{{ api_details.apis }}" + +- name: Get core API version + set_fact: + crd: "{{ api_details.apis['apiextensions.k8s.io'] }}" + host: "{{ api_details.connection['host'] }}" + client_version: "{{ api_details.version['client'] }}" + +- name: Check if all APIs are present + assert: + that: + - api_details.apis is defined + - crd is defined + - host is defined + - client_version is defined diff --git a/plugins/modules/k8s_cluster_info.py b/plugins/modules/k8s_cluster_info.py new file mode 100644 index 00000000..5142cb71 --- /dev/null +++ b/plugins/modules/k8s_cluster_info.py @@ -0,0 +1,247 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Abhijeet Kasurde +# 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 + + +DOCUMENTATION = r''' +module: k8s_cluster_info + +version_added: "0.11.1" + +short_description: Describe Kubernetes (K8s) API available and their respective versions + +author: + - Abhijeet Kasurde (@Akasurde) + +description: + - Use the OpenShift Python client to perform read operations on K8s objects. + - Authenticate using either a config file, certificates, password or token. + - Supports check mode. + +options: + invalidate_cache: + description: + - Invalidate cache before retrieving information about cluster. + type: bool + default: True +extends_documentation_fragment: + - community.kubernetes.k8s_auth_options + +requirements: + - "python >= 2.7" + - "openshift >= 0.6" + - "PyYAML >= 3.11" +''' + +EXAMPLES = r''' +- name: Get Cluster information + community.kubernetes.k8s_cluster_info: + register: api_status + +- name: Do not invalidate cache before getting information + community.kubernetes.k8s_cluster_info: + invalidate_cache: False + register: api_status + +''' + +RETURN = r''' +connection: + description: + - Connection information + returned: success + type: dict + contains: + cert_file: + description: + - Path to client certificate. + type: str + returned: success + host: + description: + - Host URL + type: str + returned: success + password: + description: + - User password + type: str + returned: success + proxy: + description: + - Proxy details + type: str + returned: success + ssl_ca_cert: + description: + - Path to CA certificate + type: str + returned: success + username: + description: + - Username + type: str + returned: success + verify_ssl: + description: + - SSL verification status + type: bool + returned: success +version: + description: + - Information about server and client version + returned: success + type: dict + contains: + server: + description: Server version + returned: success + type: dict + client: + description: Client version + returned: success + type: str +apis: + description: + - The API(s) that exists in dictionary + returned: success + type: dict + contains: + api_version: + description: API version + returned: success + type: str + categories: + description: API categories + returned: success + type: list + group_version: + description: Resource Group version + returned: success + type: str + kind: + description: Resource kind + returned: success + type: str + name: + description: Resource short name + returned: success + type: str + namespaced: + description: If resource is namespaced + returned: success + type: bool + preferred: + description: If resource version preferred + returned: success + type: bool + short_names: + description: Resource short names + returned: success + type: str + singular_name: + description: Resource singular name + returned: success + type: str + available_api_version: + description: All available versions of the given API + returned: success + type: list + preferred_api_version: + description: Preferred version of the given API + returned: success + type: str +''' + + +import copy +import traceback + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible.module_utils.parsing.convert_bool import boolean +from ansible_collections.community.kubernetes.plugins.module_utils.common import K8sAnsibleMixin, AUTH_ARG_SPEC + +try: + try: + from openshift import __version__ as version + # >=0.10 + from openshift.dynamic.resource import ResourceList + except ImportError: + # <0.10 + from openshift.dynamic.client import ResourceList + HAS_K8S_INSTANCE_HELPER = True + k8s_import_exception = None +except ImportError: + HAS_K8S_INSTANCE_HELPER = False + k8s_import_exception = traceback.format_exc() + + +class KubernetesInfoModule(K8sAnsibleMixin): + + def __init__(self): + module = AnsibleModule( + argument_spec=self.argspec, + supports_check_mode=True, + ) + self.module = module + self.params = self.module.params + + if not HAS_K8S_INSTANCE_HELPER: + self.module.fail_json(msg=missing_required_lib("openshift >= 0.6.2", reason="for merge_type"), + exception=k8s_import_exception) + + super(KubernetesInfoModule, self).__init__() + + def execute_module(self): + self.client = self.get_api_client() + invalidate_cache = boolean(self.module.params.get('invalidate_cache', True), strict=False) + if invalidate_cache: + self.client.resources.invalidate_cache() + results = {} + for resource in list(self.client.resources): + resource = resource[0] + if isinstance(resource, ResourceList): + continue + results[resource.group] = { + 'api_version': resource.group_version, + 'categories': resource.categories if resource.categories else [], + 'kind': resource.kind, + 'name': resource.name, + 'namespaced': resource.namespaced, + 'preferred': resource.preferred, + 'short_names': resource.short_names if resource.short_names else [], + 'singular_name': resource.singular_name, + } + configuration = self.client.configuration + connection = { + 'cert_file': configuration.cert_file, + 'host': configuration.host, + 'password': configuration.password, + 'proxy': configuration.proxy, + 'ssl_ca_cert': configuration.ssl_ca_cert, + 'username': configuration.username, + 'verify_ssl': configuration.verify_ssl, + } + version_info = { + 'client': version, + 'server': self.client.version, + } + self.module.exit_json(changed=False, apis=results, connection=connection, version=version_info) + + @property + def argspec(self): + spec = copy.deepcopy(AUTH_ARG_SPEC) + spec['invalidate_cache'] = dict(type='bool', default=True) + return spec + + +def main(): + KubernetesInfoModule().execute_module() + + +if __name__ == '__main__': + main()