From 7e653aee6525ab7069a3a79ad2bf4a39f26781b8 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Tue, 20 Apr 2021 12:02:14 +0530 Subject: [PATCH] k8s: Remove KubernetesRawModule dependency (#74) --- meta/runtime.yml | 5 +- plugins/modules/k8s.py | 155 ++++++++++++++++++++++++++--------------- 2 files changed, 101 insertions(+), 59 deletions(-) diff --git a/meta/runtime.yml b/meta/runtime.yml index 62df3b0..893f82f 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,6 +1,9 @@ --- -requires_ansible: '>=2.9' +requires_ansible: '>=2.9.10' plugin_routing: modules: k8s_auth: redirect: community.okd.openshift_auth + action: + k8s: + redirect: kubernetes.core.k8s_info diff --git a/plugins/modules/k8s.py b/plugins/modules/k8s.py index a3553cf..b347ba2 100644 --- a/plugins/modules/k8s.py +++ b/plugins/modules/k8s.py @@ -1,15 +1,16 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# (c) 2018, Chris Houseknecht <@chouseknecht> +# Copyright: (c) 2018, Chris Houseknecht <@chouseknecht> # 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 # STARTREMOVE (downstream) -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: k8s @@ -24,16 +25,18 @@ description: - Pass the object definition from a source file or inline. See examples for reading files and using Jinja templates or vault-encrypted files. - Access to the full range of K8s APIs. - - Use the M(k8s_info) module to obtain a list of items about an object of type C(kind) + - Use the M(kubernetes.core.k8s_info) 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. - - Optimized for OKD/OpenShift Kubernetes flavors + - Optimized for OKD/OpenShift Kubernetes flavors. extends_documentation_fragment: - kubernetes.core.k8s_state_options - kubernetes.core.k8s_name_options - kubernetes.core.k8s_resource_options - kubernetes.core.k8s_auth_options + - kubernetes.core.k8s_wait_options + - kubernetes.core.k8s_delete_options notes: - If your OpenShift Python library is not 0.9.0 or newer and you are trying to @@ -62,53 +65,6 @@ options: - strategic-merge type: list elements: str - wait: - description: - - Whether to wait for certain resource kinds to end up in the desired state. By default the module exits once Kubernetes has - received the request - - Implemented for C(state=present) for C(Deployment), C(DaemonSet) and C(Pod), and for C(state=absent) for all resource kinds. - - For resource kinds without an implementation, C(wait) returns immediately unless C(wait_condition) is set. - default: no - type: bool - wait_sleep: - description: - - Number of seconds to sleep between checks. - default: 5 - type: int - wait_timeout: - description: - - How long in seconds to wait for the resource to end up in the desired state. Ignored if C(wait) is not set. - default: 120 - type: int - wait_condition: - description: - - Specifies a custom condition on the status to wait for. Ignored if C(wait) is not set or is set to False. - suboptions: - type: - type: str - description: - - The type of condition to wait for. For example, the C(Pod) resource will set the C(Ready) condition (among others) - - Required if you are specifying a C(wait_condition). If left empty, the C(wait_condition) field will be ignored. - - The possible types for a condition are specific to each resource type in Kubernetes. See the API documentation of the status field - for a given resource to see possible choices. - status: - type: str - description: - - The value of the status field in your desired condition. - - For example, if a C(Deployment) is paused, the C(Progressing) C(type) will have the C(Unknown) status. - choices: - - True - - False - - Unknown - default: "True" - reason: - type: str - description: - - The value of the reason field in your desired condition - - For example, if a C(Deployment) is paused, The C(Progressing) C(type) will have the C(DeploymentPaused) reason. - - The possible reasons in a condition are specific to each resource type in Kubernetes. - See the API documentation of the status field for a given resource to see possible choices. - type: dict validate: description: - how (if at all) to validate the resource definition against the kubernetes schema. @@ -143,6 +99,31 @@ options: - mutually exclusive with C(merge_type) type: bool default: false + template: + description: + - Provide a valid YAML template definition file for an object when creating or updating. + - Value can be provided as string or dictionary. + - Mutually exclusive with C(src) and C(resource_definition). + - Template files needs to be present on the Ansible Controller's file system. + - Additional parameters can be specified using dictionary. + - 'Valid additional parameters - ' + - 'C(newline_sequence) (str): Specify the newline sequence to use for templating files. + valid choices are "\n", "\r", "\r\n". Default value "\n".' + - 'C(block_start_string) (str): The string marking the beginning of a block. + Default value "{%".' + - 'C(block_end_string) (str): The string marking the end of a block. + Default value "%}".' + - 'C(variable_start_string) (str): The string marking the beginning of a print statement. + Default value "{{".' + - 'C(variable_end_string) (str): The string marking the end of a print statement. + Default value "}}".' + - 'C(trim_blocks) (bool): Determine when newlines should be removed from blocks. When set to C(yes) the first newline + after a block is removed (block, not variable tag!). Default value is true.' + - 'C(lstrip_blocks) (bool): Determine when leading spaces and tabs should be stripped. + When set to C(yes) leading spaces and tabs are stripped from the start of a line to a block. + This functionality requires Jinja 2.7 or newer. Default value is false.' + type: raw + version_added: '2.0.0' requirements: - "python >= 2.7" @@ -150,7 +131,7 @@ requirements: - "PyYAML >= 3.11" ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Create a k8s namespace community.okd.k8s: name: testing @@ -223,7 +204,7 @@ EXAMPLES = ''' strict: yes ''' -RETURN = ''' +RETURN = r''' result: description: - The created, patched, or otherwise present object. Will be empty in the case of a deletion. @@ -262,21 +243,24 @@ result: ''' # ENDREMOVE (downstream) +import copy import re import operator import traceback from functools import reduce +from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_native try: - from ansible_collections.kubernetes.core.plugins.module_utils.raw import KubernetesRawModule + from ansible_collections.kubernetes.core.plugins.module_utils.common import ( + K8sAnsibleMixin, COMMON_ARG_SPEC, NAME_ARG_SPEC, + RESOURCE_ARG_SPEC, AUTH_ARG_SPEC, WAIT_ARG_SPEC, DELETE_OPTS_ARG_SPEC) HAS_KUBERNETES_COLLECTION = True except ImportError as e: HAS_KUBERNETES_COLLECTION = False k8s_collection_import_exception = e K8S_COLLECTION_ERROR = traceback.format_exc() - from ansible.module_utils.basic import AnsibleModule as KubernetesRawModule try: import yaml @@ -289,16 +273,71 @@ TRIGGER_ANNOTATION = 'image.openshift.io/triggers' TRIGGER_CONTAINER = re.compile(r"(?P.*)\[((?P[0-9]+)|\?\(@\.name==[\"'\\]*(?P[a-z0-9]([-a-z0-9]*[a-z0-9])?))") -class OKDRawModule(KubernetesRawModule): +class OKDRawModule(K8sAnsibleMixin): + + def __init__(self, k8s_kind=None, *args, **kwargs): + mutually_exclusive = [ + ('resource_definition', 'src'), + ('merge_type', 'apply'), + ('template', 'resource_definition'), + ('template', 'src'), + ] + + module = AnsibleModule( + argument_spec=self.argspec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + self.module = module + self.check_mode = self.module.check_mode + self.params = self.module.params + self.fail_json = self.module.fail_json + self.fail = self.module.fail_json + self.exit_json = self.module.exit_json - def __init__(self): if not HAS_KUBERNETES_COLLECTION: self.fail_json( msg="The kubernetes.core collection must be installed", exception=K8S_COLLECTION_ERROR, error=to_native(k8s_collection_import_exception) ) - super(OKDRawModule, self).__init__() + + super(OKDRawModule, self).__init__(*args, **kwargs) + + self.client = None + self.warnings = [] + + self.kind = k8s_kind or self.params.get('kind') + self.api_version = self.params.get('api_version') + self.name = self.params.get('name') + self.namespace = self.params.get('namespace') + + self.check_library_version() + self.set_resource_definitions() + + @property + def validate_spec(self): + return dict( + fail_on_error=dict(type='bool'), + version=dict(), + strict=dict(type='bool', default=True) + ) + + @property + def argspec(self): + argument_spec = copy.deepcopy(COMMON_ARG_SPEC) + argument_spec.update(copy.deepcopy(NAME_ARG_SPEC)) + argument_spec.update(copy.deepcopy(RESOURCE_ARG_SPEC)) + argument_spec.update(copy.deepcopy(AUTH_ARG_SPEC)) + argument_spec.update(copy.deepcopy(WAIT_ARG_SPEC)) + argument_spec['merge_type'] = dict(type='list', elements='str', choices=['json', 'merge', 'strategic-merge']) + argument_spec['validate'] = dict(type='dict', default=None, options=self.validate_spec) + argument_spec['append_hash'] = dict(type='bool', default=False) + argument_spec['apply'] = dict(type='bool', default=False) + argument_spec['template'] = dict(type='raw', default=None) + argument_spec['delete_options'] = dict(type='dict', default=None, options=copy.deepcopy(DELETE_OPTS_ARG_SPEC)) + return argument_spec def perform_action(self, resource, definition): state = self.params.get('state', None)