From 01a0815e560530fb0da543d7519b9612cad6ab37 Mon Sep 17 00:00:00 2001 From: Mike Graves Date: Thu, 6 May 2021 14:44:17 -0400 Subject: [PATCH] Replace openshift client with kubernetes client (#96) * Replace openshift client with kubernetes client This commit primarily just removes mentions of openshift from the docs and updates the requirements. Most of the work to replace the client has been done through the following commits: edc48ee5770293af78ac19ac752e7d422b402dae c214376cac0a54d2be859e37ff7cefa2e4196e7a 48c5170018b7e1869a53588e3b8efee3d93c95aa 2b6a989cf95848fc69c073f9a13f87279c889732 * Add changelog fragment * Update changelogs/fragments/96-replace-openshift-client.yaml Co-authored-by: Abhijeet Kasurde * Update plugins/modules/k8s.py Co-authored-by: Abhijeet Kasurde * Update plugins/modules/k8s_info.py Co-authored-by: Abhijeet Kasurde * Update plugins/modules/k8s_service.py Co-authored-by: Abhijeet Kasurde * Bump minimum kubernetes version to 12.0.0 Co-authored-by: Abhijeet Kasurde --- README.md | 6 +-- .../96-replace-openshift-client.yaml | 3 ++ plugins/doc_fragments/k8s_auth_options.py | 5 +- plugins/filter/k8s.py | 9 +--- plugins/inventory/k8s.py | 8 +-- plugins/lookup/k8s.py | 15 ++---- plugins/module_utils/common.py | 53 ++++++------------- plugins/modules/k8s.py | 23 +++----- plugins/modules/k8s_cluster_info.py | 6 +-- plugins/modules/k8s_exec.py | 2 +- plugins/modules/k8s_info.py | 4 +- plugins/modules/k8s_log.py | 4 +- plugins/modules/k8s_rollback.py | 4 +- plugins/modules/k8s_scale.py | 2 +- plugins/modules/k8s_service.py | 12 ++--- requirements.txt | 2 +- .../targets/kubernetes/tasks/main.yml | 6 +-- 17 files changed, 58 insertions(+), 106 deletions(-) create mode 100644 changelogs/fragments/96-replace-openshift-client.yaml diff --git a/README.md b/README.md index fd256fdf..bc6a1104 100644 --- a/README.md +++ b/README.md @@ -79,11 +79,11 @@ collections: version: 1.2.0 ``` -### Installing the OpenShift Python Library +### Installing the Kubernetes Python Library -Content in this collection requires the [OpenShift Python client](https://pypi.org/project/openshift/) to interact with Kubernetes' APIs. You can install it with: +Content in this collection requires the [Kubernetes Python client](https://pypi.org/project/kubernetes/) to interact with Kubernetes' APIs. You can install it with: - pip3 install openshift + pip3 install kubernetes ### Using modules from the Kubernetes Collection in your playbooks diff --git a/changelogs/fragments/96-replace-openshift-client.yaml b/changelogs/fragments/96-replace-openshift-client.yaml new file mode 100644 index 00000000..136adace --- /dev/null +++ b/changelogs/fragments/96-replace-openshift-client.yaml @@ -0,0 +1,3 @@ +--- +major_changes: + - replaces the openshift client with the official kubernetes client (https://github.com/ansible-collections/kubernetes.core/issues/34). diff --git a/plugins/doc_fragments/k8s_auth_options.py b/plugins/doc_fragments/k8s_auth_options.py index d63fbbc2..0012a40d 100644 --- a/plugins/doc_fragments/k8s_auth_options.py +++ b/plugins/doc_fragments/k8s_auth_options.py @@ -24,7 +24,7 @@ options: 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 + options are provided, the Kubernetes client will attempt to load the default configuration file from I(~/.kube/config). Can also be specified via K8S_AUTH_KUBECONFIG environment variable. type: path @@ -110,9 +110,6 @@ options: - "The fix for this k8s python library is here: https://github.com/kubernetes-client/python-base/pull/169" type: bool 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" - "To avoid SSL certificate validation errors when C(validate_certs) is I(True), the full certificate chain for the API server must be provided via C(ca_cert) or in the kubeconfig file." diff --git a/plugins/filter/k8s.py b/plugins/filter/k8s.py index 3597b852..7b8591ef 100644 --- a/plugins/filter/k8s.py +++ b/plugins/filter/k8s.py @@ -6,18 +6,11 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -try: - from openshift.helper.hashes import generate_hash - HAS_GENERATE_HASH = True -except ImportError: - HAS_GENERATE_HASH = False - from ansible.errors import AnsibleFilterError +from ansible_collections.kubernetes.core.plugins.module_utils.hashes import generate_hash def k8s_config_resource_name(resource): - if not HAS_GENERATE_HASH: - raise AnsibleFilterError("k8s_config_resource_name requires openshift>=0.7.2") try: return resource['metadata']['name'] + '-' + generate_hash(resource) except KeyError: diff --git a/plugins/inventory/k8s.py b/plugins/inventory/k8s.py index df348dc2..01c2ebc3 100644 --- a/plugins/inventory/k8s.py +++ b/plugins/inventory/k8s.py @@ -37,7 +37,7 @@ DOCUMENTATION = ''' 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 + options are provided, the Kubernetes client will attempt to load the default configuration file from I(~/.kube/config). Can also be specified via K8S_AUTH_KUBECONFIG environment variable. context: @@ -87,7 +87,7 @@ DOCUMENTATION = ''' requirements: - "python >= 3.6" - - "openshift >= 0.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" ''' @@ -121,7 +121,7 @@ from ansible_collections.kubernetes.core.plugins.module_utils.common import K8sA from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable try: - from openshift.dynamic.exceptions import DynamicApiError + from kubernetes.dynamic.exceptions import DynamicApiError except ImportError: pass @@ -158,7 +158,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, K8sAnsibleM if not HAS_K8S_MODULE_HELPER: raise K8sInventoryException( - "This module requires the OpenShift Python client. Try `pip install openshift`. Detail: {0}".format(k8s_import_exception) + "This module requires the Kubernetes Python client. Try `pip install kubernetes`. Detail: {0}".format(k8s_import_exception) ) source_data = None diff --git a/plugins/lookup/k8s.py b/plugins/lookup/k8s.py index b3728be5..e363d1e3 100644 --- a/plugins/lookup/k8s.py +++ b/plugins/lookup/k8s.py @@ -30,7 +30,7 @@ DOCUMENTATION = ''' - Fabian von Feilitzsch <@fabianvf> description: - - Uses the OpenShift Python client to fetch a specific object by name, all matching objects within a + - Uses the Kubernetes Python client to fetch a specific object by name, all matching objects within a namespace, or all matching objects for all namespaces, as well as information about the cluster. - Provides access the full range of K8s APIs. - Enables authentication via config file, certificates, password or token. @@ -85,7 +85,7 @@ DOCUMENTATION = ''' 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 + options are provided, the Kubernetes client will attempt to load the default configuration file from I(~/.kube/config). Can also be specified via K8S_AUTH_KUBECONFIG environment variable. context: @@ -125,13 +125,8 @@ DOCUMENTATION = ''' requirements: - "python >= 3.6" - - "openshift >= 0.6" + - "kubernetes >= 12.0.0" - "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 = """ @@ -206,7 +201,7 @@ from ansible_collections.kubernetes.core.plugins.module_utils.common import K8sA try: - from openshift.dynamic.exceptions import NotFoundError + from kubernetes.dynamic.exceptions import NotFoundError HAS_K8S_MODULE_HELPER = True k8s_import_exception = None except ImportError as e: @@ -220,7 +215,7 @@ class KubernetesLookup(K8sAnsibleMixin): if not HAS_K8S_MODULE_HELPER: raise Exception( - "Requires the OpenShift Python client. Try `pip install openshift`. Detail: {0}".format(k8s_import_exception) + "Requires the Kubernetes Python client. Try `pip install kubernetes`. Detail: {0}".format(k8s_import_exception) ) self.kind = None diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 9a7cb269..86b7ae9a 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -39,10 +39,10 @@ from ansible.module_utils.parsing.convert_bool import boolean K8S_IMP_ERR = None try: import kubernetes - import openshift from kubernetes.dynamic.exceptions import ( NotFoundError, ResourceNotFoundError, ResourceNotUniqueError, DynamicApiError, - ConflictError, ForbiddenError, MethodNotAllowedError, BadRequestError + ConflictError, ForbiddenError, MethodNotAllowedError, BadRequestError, + KubernetesValidateMissing ) HAS_K8S_MODULE_HELPER = True k8s_import_exception = None @@ -69,14 +69,6 @@ except ImportError: YAML_IMP_ERR = traceback.format_exc() HAS_YAML = False -K8S_CONFIG_HASH_IMP_ERR = None -try: - from kubernetes.dynamic.exceptions import KubernetesValidateMissing - HAS_K8S_CONFIG_HASH = True -except ImportError: - K8S_CONFIG_HASH_IMP_ERR = traceback.format_exc() - HAS_K8S_CONFIG_HASH = False - HAS_K8S_APPLY = None try: from ansible_collections.kubernetes.core.plugins.module_utils.apply import apply_object @@ -229,9 +221,9 @@ class K8sAnsibleMixin(object): def __init__(self, module, *args, **kwargs): if not HAS_K8S_MODULE_HELPER: - module.fail_json(msg=missing_required_lib('openshift'), exception=K8S_IMP_ERR, + module.fail_json(msg=missing_required_lib('kubernetes'), exception=K8S_IMP_ERR, error=to_native(k8s_import_exception)) - self.openshift_version = openshift.__version__ + self.kubernetes_version = kubernetes.__version__ if not HAS_YAML: module.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR) @@ -495,21 +487,8 @@ class K8sAnsibleMixin(object): self.resource_definitions = [implicit_definition] def check_library_version(self): - validate = self.params.get('validate') - if validate and LooseVersion(self.openshift_version) < LooseVersion("0.8.0"): - self.fail_json(msg="openshift >= 0.8.0 is required for validate") - self.append_hash = self.params.get('append_hash') - if self.append_hash and not HAS_K8S_CONFIG_HASH: - self.fail_json(msg=missing_required_lib("openshift >= 0.7.2", reason="for append_hash"), - exception=K8S_CONFIG_HASH_IMP_ERR) - if self.params['merge_type'] and LooseVersion(self.openshift_version) < LooseVersion("0.6.2"): - self.fail_json(msg=missing_required_lib("openshift >= 0.6.2", reason="for merge_type")) - self.apply = self.params.get('apply', False) - if self.apply and not HAS_K8S_APPLY: - self.fail_json(msg=missing_required_lib("openshift >= 0.9.2", reason="for apply")) - wait = self.params.get('wait', False) - if wait and not HAS_K8S_INSTANCE_HELPER: - self.fail_json(msg=missing_required_lib("openshift >= 0.4.0", reason="for wait")) + if LooseVersion(self.kubernetes_version) < LooseVersion("12.0.0"): + self.fail_json(msg="kubernetes >= 12.0.0 is required") def flatten_list_kind(self, list_resource, definitions): flattened = [] @@ -590,6 +569,8 @@ class K8sAnsibleMixin(object): return definition def perform_action(self, resource, definition): + append_hash = self.params.get('append_hash', False) + apply = self.params.get('apply', False) delete_options = self.params.get('delete_options') result = {'changed': False, 'result': {}} state = self.params.get('state', None) @@ -613,7 +594,7 @@ class K8sAnsibleMixin(object): try: # ignore append_hash for resources other than ConfigMap and Secret - if self.append_hash and definition['kind'] in ['ConfigMap', 'Secret']: + if append_hash and definition['kind'] in ['ConfigMap', 'Secret']: name = '%s-%s' % (name, generate_hash(definition)) definition['metadata']['name'] = name params = dict(name=name) @@ -690,7 +671,7 @@ class K8sAnsibleMixin(object): self.fail_json(msg=build_error_msg(definition['kind'], origin_name, msg), **result) return result else: - if self.apply: + if apply: if self.check_mode: ignored, patch = apply_object(resource, _encode_stringdata(definition)) if existing: @@ -786,7 +767,7 @@ class K8sAnsibleMixin(object): k8s_obj = _encode_stringdata(definition) else: try: - k8s_obj = resource.replace(definition, name=name, namespace=namespace, append_hash=self.append_hash).to_dict() + k8s_obj = resource.replace(definition, name=name, namespace=namespace, append_hash=append_hash).to_dict() except DynamicApiError as exc: msg = "Failed to replace object: {0}".format(exc.body) if self.warnings: @@ -819,15 +800,11 @@ class K8sAnsibleMixin(object): if self.check_mode: k8s_obj = dict_merge(existing.to_dict(), _encode_stringdata(definition)) else: - if LooseVersion(self.openshift_version) < LooseVersion("0.6.2"): + for merge_type in self.params['merge_type'] or ['strategic-merge', 'merge']: k8s_obj, error = self.patch_resource(resource, definition, existing, name, - namespace) - else: - for merge_type in self.params['merge_type'] or ['strategic-merge', 'merge']: - k8s_obj, error = self.patch_resource(resource, definition, existing, name, - namespace, merge_type=merge_type) - if not error: - break + namespace, merge_type=merge_type) + if not error: + break if error: if continue_on_error: result['error'] = error diff --git a/plugins/modules/k8s.py b/plugins/modules/k8s.py index ea21c8ac..f70923ff 100644 --- a/plugins/modules/k8s.py +++ b/plugins/modules/k8s.py @@ -21,7 +21,7 @@ author: - "Fabian von Feilitzsch (@fabianvf)" description: - - Use the OpenShift Python client to perform CRUD operations on K8s objects. + - Use the Kubernetes Python client to perform CRUD operations on K8s objects. - 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. @@ -37,13 +37,6 @@ extends_documentation_fragment: - 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 - remove an item from an associative array/dictionary, for example a label or - an annotation, you will need to explicitly set the value of the item to be - removed to `null`. Simply deleting the entry in the dictionary will not - remove it from openshift or kubernetes. - options: merge_type: description: @@ -52,11 +45,9 @@ options: - For example, Custom Resource Definitions typically aren't updatable by the usual strategic merge. You may want to use C(merge) if you see "strategic merge patch format is not supported" - See U(https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/#use-a-json-merge-patch-to-update-a-deployment) - - Requires openshift >= 0.6.2 - - If more than one merge_type is given, the merge_types will be tried in order - - If openshift >= 0.6.2, this defaults to C(['strategic-merge', 'merge']), which is ideal for using the same parameters - on resource kinds that combine Custom Resources and built-in resources. For openshift < 0.6.2, the default - is simply C(strategic-merge). + - If more than one C(merge_type) is given, the merge_types will be tried in order. This defaults to + C(['strategic-merge', 'merge']), which is ideal for using the same parameters on resource kinds that + combine Custom Resources and built-in resources. - mutually exclusive with C(apply) choices: - json @@ -67,7 +58,7 @@ options: validate: description: - how (if at all) to validate the resource definition against the kubernetes schema. - Requires the kubernetes-validate python module and openshift >= 0.8.0 + Requires the kubernetes-validate python module. suboptions: fail_on_error: description: whether to fail on validation errors. @@ -88,7 +79,6 @@ options: - The full definition of an object is needed to generate the hash - this means that deleting an object created with append_hash will only work if the same object is passed with state=absent (alternatively, just use state=absent with the name including the generated hash and append_hash=no) - - Requires openshift >= 0.7.2 default: False type: bool apply: @@ -96,7 +86,6 @@ options: - C(apply) compares the desired resource definition with the previously supplied resource definition, ignoring properties that are automatically generated - C(apply) works better with Services than 'force=yes' - - Requires openshift >= 0.9.2 - mutually exclusive with C(merge_type) default: False type: bool @@ -134,7 +123,7 @@ options: requirements: - "python >= 3.6" - - "openshift >= 0.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" - "jsonpatch" ''' diff --git a/plugins/modules/k8s_cluster_info.py b/plugins/modules/k8s_cluster_info.py index 04cc09d8..b17f07be 100644 --- a/plugins/modules/k8s_cluster_info.py +++ b/plugins/modules/k8s_cluster_info.py @@ -18,7 +18,7 @@ author: - Abhijeet Kasurde (@Akasurde) description: - - Use the OpenShift Python client to perform read operations on K8s objects. + - Use the Kubernetes Python client to perform read operations on K8s objects. - Authenticate using either a config file, certificates, password or token. - Supports check mode. @@ -34,7 +34,7 @@ extends_documentation_fragment: requirements: - "python >= 3.6" - - "openshift >= 0.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" ''' @@ -186,7 +186,7 @@ def execute_module(module, client): 'username': configuration.username, 'verify_ssl': configuration.verify_ssl, } - from openshift import __version__ as version + from kubernetes import __version__ as version version_info = { 'client': version, 'server': client.version, diff --git a/plugins/modules/k8s_exec.py b/plugins/modules/k8s_exec.py index b1ab1103..b72df56e 100644 --- a/plugins/modules/k8s_exec.py +++ b/plugins/modules/k8s_exec.py @@ -27,7 +27,7 @@ extends_documentation_fragment: requirements: - "python >= 3.6" - - "openshift == 0.4.3" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" notes: diff --git a/plugins/modules/k8s_info.py b/plugins/modules/k8s_info.py index f2ab9eb1..50059e41 100644 --- a/plugins/modules/k8s_info.py +++ b/plugins/modules/k8s_info.py @@ -18,7 +18,7 @@ author: - "Will Thames (@willthames)" description: - - Use the OpenShift Python client to perform read operations on K8s objects. + - Use the Kubernetes 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. @@ -50,7 +50,7 @@ extends_documentation_fragment: requirements: - "python >= 3.6" - - "openshift >= 0.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" ''' diff --git a/plugins/modules/k8s_log.py b/plugins/modules/k8s_log.py index 281cb192..e3be18bf 100644 --- a/plugins/modules/k8s_log.py +++ b/plugins/modules/k8s_log.py @@ -20,7 +20,7 @@ author: - "Fabian von Feilitzsch (@fabianvf)" description: - - Use the OpenShift Python client to perform read operations on K8s log endpoints. + - Use the Kubernetes Python client to perform read operations on K8s log endpoints. - Authenticate using either a config file, certificates, password or token. - Supports check mode. - Analogous to `kubectl logs` or `oc logs` @@ -57,7 +57,7 @@ options: requirements: - "python >= 3.6" - - "openshift >= 0.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" ''' diff --git a/plugins/modules/k8s_rollback.py b/plugins/modules/k8s_rollback.py index 06d82904..f12d3da4 100644 --- a/plugins/modules/k8s_rollback.py +++ b/plugins/modules/k8s_rollback.py @@ -15,7 +15,7 @@ version_added: "1.0.0" author: - "Julien Huon (@julienhuon)" description: - - Use the OpenShift Python client to perform the Rollback. + - Use the Kubernetes Python client to perform the Rollback. - Authenticate using either a config file, certificates, password or token. - Similar to the C(kubectl rollout undo) command. options: @@ -32,7 +32,7 @@ extends_documentation_fragment: - kubernetes.core.k8s_name_options requirements: - "python >= 3.6" - - "openshift >= 0.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" ''' diff --git a/plugins/modules/k8s_scale.py b/plugins/modules/k8s_scale.py index e4f80b97..e4643aad 100644 --- a/plugins/modules/k8s_scale.py +++ b/plugins/modules/k8s_scale.py @@ -32,7 +32,7 @@ extends_documentation_fragment: requirements: - "python >= 3.6" - - "openshift >= 0.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" ''' diff --git a/plugins/modules/k8s_service.py b/plugins/modules/k8s_service.py index aeee768d..d94ba5c0 100644 --- a/plugins/modules/k8s_service.py +++ b/plugins/modules/k8s_service.py @@ -18,7 +18,7 @@ short_description: Manage Services on Kubernetes author: KubeVirt Team (@kubevirt) description: - - Use Openshift Python SDK to manage Services on Kubernetes + - Use Kubernetes Python SDK to manage Services on Kubernetes extends_documentation_fragment: - kubernetes.core.k8s_auth_options @@ -33,11 +33,9 @@ options: - For example, Custom Resource Definitions typically aren't updatable by the usual strategic merge. You may want to use C(merge) if you see "strategic merge patch format is not supported" - See U(https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/#use-a-json-merge-patch-to-update-a-deployment) - - Requires openshift >= 0.6.2 - - If more than one merge_type is given, the merge_types will be tried in order - - If openshift >= 0.6.2, this defaults to C(['strategic-merge', 'merge']), which is ideal for using the same parameters - on resource kinds that combine Custom Resources and built-in resources. For openshift < 0.6.2, the default - is simply C(strategic-merge). + - If more than one C(merge_type) is given, the merge_types will be tried in order + - This defaults to C(['strategic-merge', 'merge']), which is ideal for using the same parameters + on resource kinds that combine Custom Resources and built-in resources. choices: - json - merge @@ -86,7 +84,7 @@ options: requirements: - python >= 3.6 - - openshift >= 0.6.2 + - kubernetes >= 12.0.0 ''' EXAMPLES = r''' diff --git a/requirements.txt b/requirements.txt index 9b495b2b..cea80595 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -openshift>=0.6.2 +kubernetes>=12.0.0 requests-oauthlib jsonpatch diff --git a/tests/integration/targets/kubernetes/tasks/main.yml b/tests/integration/targets/kubernetes/tasks/main.yml index abeb2a23..52fae25f 100644 --- a/tests/integration/targets/kubernetes/tasks/main.yml +++ b/tests/integration/targets/kubernetes/tasks/main.yml @@ -12,7 +12,7 @@ - pip: name: - - openshift>=0.9.2 + - kubernetes>=12.0.0 - coverage>=5.3 virtualenv: "{{ virtualenv }}" virtualenv_command: "{{ virtualenv_command }}" @@ -32,7 +32,7 @@ - pip: name: - kubernetes-validate==1.12.0 - - openshift>=0.9.2 + - kubernetes>=12.0.0 - coverage>=5.3 virtualenv: "{{ virtualenv }}" virtualenv_command: "{{ virtualenv_command }}" @@ -60,7 +60,7 @@ - pip: name: - - openshift>=0.9.2 + - kubernetes>=12.0.0 virtualenv: "{{ virtualenv }}" virtualenv_command: "{{ virtualenv_command }}" virtualenv_site_packages: no