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