diff --git a/README.md b/README.md index f41044b..411902d 100644 --- a/README.md +++ b/README.md @@ -61,11 +61,11 @@ collections: version: 1.1.2 ``` -### 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 OKD Collection in your playbooks diff --git a/changelogs/fragments/93-update-to-k8s-2.yaml b/changelogs/fragments/93-update-to-k8s-2.yaml new file mode 100644 index 0000000..23b419e --- /dev/null +++ b/changelogs/fragments/93-update-to-k8s-2.yaml @@ -0,0 +1,5 @@ +--- +breaking_changes: + - drop python 2 support (https://github.com/openshift/community.okd/pull/93). +major_changes: + - update to use kubernetes.core 2.0 (https://github.com/openshift/community.okd/pull/93). diff --git a/ci/Dockerfile b/ci/Dockerfile index b63be8c..50b3195 100644 --- a/ci/Dockerfile +++ b/ci/Dockerfile @@ -16,7 +16,7 @@ RUN yum install -y \ python3-setuptools \ && pip3 install --no-cache-dir --upgrade setuptools pip \ && pip3 install --no-cache-dir \ - openshift \ + kubernetes \ ansible==2.9.* \ "molecule<3.3.0" \ && yum clean all \ diff --git a/galaxy.yml b/galaxy.yml index f12a1a9..fb3ac50 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -5,7 +5,7 @@ authors: - willthames (https://github.com/willthames) - Akasurde (https://github.com/akasurde) dependencies: - kubernetes.core: '>=1.2.0,<1.3.0' + kubernetes.core: '>=2.0.0,<2.1.0' description: OKD Collection for Ansible. documentation: '' homepage: '' diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index 10f3e99..9d26da9 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -10,7 +10,7 @@ - pip: name: - - openshift>=0.9.2 + - kubernetes>=12.0.0 - coverage virtualenv: "{{ virtualenv }}" virtualenv_command: "{{ virtualenv_command }}" diff --git a/plugins/inventory/openshift.py b/plugins/inventory/openshift.py index 7871bd5..26cee4f 100644 --- a/plugins/inventory/openshift.py +++ b/plugins/inventory/openshift.py @@ -36,8 +36,8 @@ 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 - configuration file from I(~/.kube/config.json). Can also be specified via K8S_AUTH_KUBECONFIG + 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: description: @@ -85,8 +85,8 @@ DOCUMENTATION = ''' to access. requirements: - - "python >= 2.7" - - "openshift >= 0.6" + - "python >= 3.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" ''' @@ -114,9 +114,10 @@ connections: ''' from ansible_collections.kubernetes.core.plugins.inventory.k8s import K8sInventoryException, InventoryModule as K8sInventoryModule, format_dynamic_api_exc +from ansible_collections.kubernetes.core.plugins.module_utils.common import get_api_client try: - from openshift.dynamic.exceptions import DynamicApiError + from kubernetes.dynamic.exceptions import DynamicApiError except ImportError: pass @@ -135,7 +136,7 @@ class InventoryModule(K8sInventoryModule): raise K8sInventoryException("Expecting connections to be a list.") for connection in connections: - client = self.get_api_client(**connection) + client = get_api_client(**connection) name = connection.get('name', self.get_default_host_name(client.configuration.host)) if connection.get('namespaces'): namespaces = connection['namespaces'] @@ -144,7 +145,7 @@ class InventoryModule(K8sInventoryModule): for namespace in namespaces: self.get_routes_for_namespace(client, name, namespace) else: - client = self.get_api_client() + client = get_api_client() name = self.get_default_host_name(client.configuration.host) namespaces = self.get_available_namespaces(client) for namespace in namespaces: diff --git a/plugins/modules/k8s.py b/plugins/modules/k8s.py index b347ba2..3ba3fde 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. @@ -31,21 +31,28 @@ description: - 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 - 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: + state: + description: + - Determines if an object should be created, patched, or deleted. When set to C(present), an object will be + created, if it does not already exist. If set to C(absent), an existing object will be deleted. If set to + C(present), an existing object will be patched, if its attributes differ from those specified using + I(resource_definition) or I(src). + - C(patched) state is an existing resource that has a given patch applied. If the resource doesn't exist, silently skip it (do not raise an error). + type: str + default: present + choices: [ absent, present, patched ] + force: + description: + - If set to C(yes), and I(state) is C(present), an existing object will be replaced. + type: bool + default: no merge_type: description: - Whether to override the default patch merge approach with a specific type. By default, the strategic @@ -53,12 +60,11 @@ 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). + - 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) + - I(merge_type=json) is deprecated and will be removed in version 3.0.0. Please use M(kubernetes.core.k8s_json_patch) instead. choices: - json - merge @@ -124,10 +130,17 @@ options: This functionality requires Jinja 2.7 or newer. Default value is false.' type: raw version_added: '2.0.0' + continue_on_error: + description: + - Whether to continue on creation/deletion errors when multiple resources are defined. + - This has no effect on the validation step which is controlled by the C(validate.fail_on_error) parameter. + type: bool + default: False + version_added: 2.0.0 requirements: - - "python >= 2.7" - - "openshift >= 0.6" + - "python >= 3.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" ''' @@ -240,6 +253,10 @@ result: returned: when C(wait) is true type: int sample: 48 + error: + description: error while trying to create/delete the object. + returned: error + type: complex ''' # ENDREMOVE (downstream) @@ -253,9 +270,9 @@ from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_native try: - 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) + from ansible_collections.kubernetes.core.plugins.module_utils.common import get_api_client, K8sAnsibleMixin + from ansible_collections.kubernetes.core.plugins.module_utils.args_common import ( + 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 @@ -264,7 +281,7 @@ except ImportError as e: try: import yaml - from openshift.dynamic.exceptions import DynamicApiError, NotFoundError, ForbiddenError + from kubernetes.dynamic.exceptions import DynamicApiError, NotFoundError, ForbiddenError except ImportError: # Exceptions handled in common pass @@ -303,9 +320,9 @@ class OKDRawModule(K8sAnsibleMixin): error=to_native(k8s_collection_import_exception) ) - super(OKDRawModule, self).__init__(*args, **kwargs) + super(OKDRawModule, self).__init__(module, *args, **kwargs) - self.client = None + self.client = get_api_client(module) self.warnings = [] self.kind = k8s_kind or self.params.get('kind') @@ -314,7 +331,7 @@ class OKDRawModule(K8sAnsibleMixin): self.namespace = self.params.get('namespace') self.check_library_version() - self.set_resource_definitions() + self.set_resource_definitions(module) @property def validate_spec(self): @@ -326,8 +343,7 @@ class OKDRawModule(K8sAnsibleMixin): @property def argspec(self): - argument_spec = copy.deepcopy(COMMON_ARG_SPEC) - argument_spec.update(copy.deepcopy(NAME_ARG_SPEC)) + argument_spec = 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)) @@ -337,6 +353,9 @@ class OKDRawModule(K8sAnsibleMixin): 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)) + argument_spec['continue_on_error'] = dict(type='bool', default=False) + argument_spec['state'] = dict(default='present', choices=['present', 'absent', 'patched']) + argument_spec['force'] = dict(type='bool', default=False) return argument_spec def perform_action(self, resource, definition): diff --git a/plugins/modules/openshift_auth.py b/plugins/modules/openshift_auth.py index 2e5160c..c897bda 100644 --- a/plugins/modules/openshift_auth.py +++ b/plugins/modules/openshift_auth.py @@ -70,7 +70,7 @@ options: type: str requirements: - - python >= 2.7 + - python >= 3.6 - urllib3 - requests - requests-oauthlib diff --git a/plugins/modules/openshift_process.py b/plugins/modules/openshift_process.py index c63bd01..e399eed 100644 --- a/plugins/modules/openshift_process.py +++ b/plugins/modules/openshift_process.py @@ -29,8 +29,8 @@ extends_documentation_fragment: - kubernetes.core.k8s_resource_options requirements: - - "python >= 2.7" - - "openshift >= 0.11.0" + - "python >= 3.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" options: @@ -212,8 +212,9 @@ from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_native try: - from ansible_collections.kubernetes.core.plugins.module_utils.common import ( - K8sAnsibleMixin, AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, WAIT_ARG_SPEC + from ansible_collections.kubernetes.core.plugins.module_utils.common import K8sAnsibleMixin, get_api_client + from ansible_collections.kubernetes.core.plugins.module_utils.args_common import ( + AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, WAIT_ARG_SPEC ) HAS_KUBERNETES_COLLECTION = True except ImportError as e: @@ -224,7 +225,7 @@ except ImportError as e: AUTH_ARG_SPEC = RESOURCE_ARG_SPEC = WAIT_ARG_SPEC = {} try: - from openshift.dynamic.exceptions import DynamicApiError, NotFoundError + from kubernetes.dynamic.exceptions import DynamicApiError, NotFoundError except ImportError: pass @@ -248,7 +249,7 @@ class OpenShiftProcess(K8sAnsibleMixin): error=to_native(k8s_collection_import_exception) ) - super(OpenShiftProcess, self).__init__() + super(OpenShiftProcess, self).__init__(self.module) self.params = self.module.params self.check_mode = self.module.check_mode @@ -269,7 +270,7 @@ class OpenShiftProcess(K8sAnsibleMixin): return spec def execute_module(self): - self.client = self.get_api_client() + self.client = get_api_client(self.module) v1_templates = self.find_resource('templates', 'template.openshift.io/v1', fail=True) v1_processed_templates = self.find_resource('processedtemplates', 'template.openshift.io/v1', fail=True) @@ -294,7 +295,7 @@ class OpenShiftProcess(K8sAnsibleMixin): template = None if src or definition: - self.set_resource_definitions() + self.set_resource_definitions(self.module) if len(self.resource_definitions) < 1: self.fail_json('Unable to load a Template resource from src or resource_definition') elif len(self.resource_definitions) > 1: diff --git a/plugins/modules/openshift_route.py b/plugins/modules/openshift_route.py index ba672bc..0a7a9c4 100644 --- a/plugins/modules/openshift_route.py +++ b/plugins/modules/openshift_route.py @@ -29,8 +29,8 @@ extends_documentation_fragment: - kubernetes.core.k8s_state_options requirements: - - "python >= 2.7" - - "openshift >= 0.11.0" + - "python >= 3.6" + - "kubernetes >= 12.0.0" - "PyYAML >= 3.11" options: @@ -305,8 +305,9 @@ from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_native try: - from ansible_collections.kubernetes.core.plugins.module_utils.common import ( - K8sAnsibleMixin, AUTH_ARG_SPEC, WAIT_ARG_SPEC, COMMON_ARG_SPEC + from ansible_collections.kubernetes.core.plugins.module_utils.common import K8sAnsibleMixin, get_api_client + from ansible_collections.kubernetes.core.plugins.module_utils.args_common import ( + AUTH_ARG_SPEC, WAIT_ARG_SPEC, COMMON_ARG_SPEC ) HAS_KUBERNETES_COLLECTION = True except ImportError as e: @@ -317,7 +318,7 @@ except ImportError as e: AUTH_ARG_SPEC = WAIT_ARG_SPEC = COMMON_ARG_SPEC = {} try: - from openshift.dynamic.exceptions import DynamicApiError, NotFoundError + from kubernetes.dynamic.exceptions import DynamicApiError, NotFoundError except ImportError: pass @@ -338,7 +339,7 @@ class OpenShiftRoute(K8sAnsibleMixin): error=to_native(k8s_collection_import_exception) ) - super(OpenShiftRoute, self).__init__() + super(OpenShiftRoute, self).__init__(self.module) self.params = self.module.params # TODO: should probably make it so that at least some of these aren't required for perform_action to work @@ -375,7 +376,7 @@ class OpenShiftRoute(K8sAnsibleMixin): return spec def execute_module(self): - self.client = self.get_api_client() + self.client = get_api_client(self.module) v1_routes = self.find_resource('Route', 'route.openshift.io/v1', fail=True) service_name = self.params.get('service') diff --git a/requirements.txt b/requirements.txt index 6ed70a7..8de830e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -openshift>=0.6.2 +kubernetes>=12.0.0 requests-oauthlib diff --git a/requirements.yml b/requirements.yml index 77ada44..6bd11ea 100644 --- a/requirements.yml +++ b/requirements.yml @@ -1,3 +1,3 @@ collections: - name: kubernetes.core - version: '>=1.2.0,<1.3.0' + version: '>=2.0.0,<2.1.0'