From a23d454365741bdb373c05f415ef0c3866760b92 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Mon, 4 May 2020 16:24:51 +1000 Subject: [PATCH 01/88] Add failing test for service in check mode --- molecule/default/tasks/apply.yml | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/molecule/default/tasks/apply.yml b/molecule/default/tasks/apply.yml index f5362220..2f8e6e28 100644 --- a/molecule/default/tasks/apply.yml +++ b/molecule/default/tasks/apply.yml @@ -154,6 +154,30 @@ that: - k8s_service_2 is not changed + - name: Add exactly same service in check mode + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: http + port: 8080 + targetPort: 8080 + apply: yes + register: k8s_service_3 + check_mode: yes + + - name: Check nothing changed + assert: + that: + - k8s_service_3 is not changed + - name: Change service ports k8s: definition: @@ -170,14 +194,14 @@ port: 8081 targetPort: 8081 apply: yes - register: k8s_service_3 + register: k8s_service_4 - name: Check ports are correct assert: that: - - k8s_service_3 is changed - - k8s_service_3.result.spec.ports | length == 1 - - k8s_service_3.result.spec.ports[0].port == 8081 + - k8s_service_4 is changed + - k8s_service_4.result.spec.ports | length == 1 + - k8s_service_4.result.spec.ports[0].port == 8081 always: - name: Remove namespace From 34137c40c220170dd1c6c2bc6c2d2fef834200b7 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Mon, 4 May 2020 18:48:13 +1000 Subject: [PATCH 02/88] Fix apply patching results in check mode apply_object returns only the patch - we need to actually apply the patch to the existing object. Fixes ansible/ansible#66780 --- molecule/default/molecule.yml | 2 ++ plugins/module_utils/raw.py | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 90ba2e53..37f7c3bc 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -21,6 +21,8 @@ provisioner: ansible_python_interpreter: '{{ ansible_playbook_python }}' env: ANSIBLE_FORCE_COLOR: 'true' + options: + vvv: True scenario: name: default test_sequence: diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index de214e90..929193b1 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -299,7 +299,11 @@ class KubernetesRawModule(KubernetesAnsibleModule): else: if self.apply: if self.check_mode: - ignored, k8s_obj = apply_object(resource, definition) + ignored, patch = apply_object(resource, definition) + if existing: + k8s_obj = dict_merge(existing.to_dict(), patch) + else: + k8s_obj = patch else: try: k8s_obj = resource.apply(definition, namespace=namespace).to_dict() From f45d33224fc90a57e5231653f62e53fa51a19747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rjan=20Sj=C3=B6holm?= Date: Thu, 14 May 2020 14:25:07 +0200 Subject: [PATCH 03/88] Remove ANSIBLE_METADATA The meta data field is deprecated and is not used anymore. See ansible-collections/overview#57 for more details. --- plugins/filter/k8s.py | 7 ------- plugins/modules/helm.py | 3 --- plugins/modules/helm_info.py | 3 --- plugins/modules/helm_repository.py | 3 --- plugins/modules/k8s.py | 4 ---- plugins/modules/k8s_auth.py | 4 ---- plugins/modules/k8s_exec.py | 4 ---- plugins/modules/k8s_info.py | 4 ---- plugins/modules/k8s_log.py | 4 ---- plugins/modules/k8s_scale.py | 3 --- plugins/modules/k8s_service.py | 4 ---- .../targets/kubernetes/library/test_tempfile.py | 3 --- 12 files changed, 46 deletions(-) diff --git a/plugins/filter/k8s.py b/plugins/filter/k8s.py index f6cb0579..3597b852 100644 --- a/plugins/filter/k8s.py +++ b/plugins/filter/k8s.py @@ -6,13 +6,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community' -} - - try: from openshift.helper.hashes import generate_hash HAS_GENERATE_HASH = True diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 2cdd9672..0af2b2ea 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -6,9 +6,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} DOCUMENTATION = ''' --- diff --git a/plugins/modules/helm_info.py b/plugins/modules/helm_info.py index 5d773c21..382623e3 100644 --- a/plugins/modules/helm_info.py +++ b/plugins/modules/helm_info.py @@ -6,9 +6,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} DOCUMENTATION = ''' --- diff --git a/plugins/modules/helm_repository.py b/plugins/modules/helm_repository.py index 908c0418..95560933 100644 --- a/plugins/modules/helm_repository.py +++ b/plugins/modules/helm_repository.py @@ -6,9 +6,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} DOCUMENTATION = ''' --- diff --git a/plugins/modules/k8s.py b/plugins/modules/k8s.py index 13cb985a..b7581f4d 100644 --- a/plugins/modules/k8s.py +++ b/plugins/modules/k8s.py @@ -9,10 +9,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - DOCUMENTATION = ''' module: k8s diff --git a/plugins/modules/k8s_auth.py b/plugins/modules/k8s_auth.py index 4184ff40..a02a5257 100644 --- a/plugins/modules/k8s_auth.py +++ b/plugins/modules/k8s_auth.py @@ -9,10 +9,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - DOCUMENTATION = ''' module: k8s_auth diff --git a/plugins/modules/k8s_exec.py b/plugins/modules/k8s_exec.py index 649b58ef..65ceb79d 100644 --- a/plugins/modules/k8s_exec.py +++ b/plugins/modules/k8s_exec.py @@ -9,10 +9,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - DOCUMENTATION = ''' module: k8s_exec diff --git a/plugins/modules/k8s_info.py b/plugins/modules/k8s_info.py index 4498cab8..442a4209 100644 --- a/plugins/modules/k8s_info.py +++ b/plugins/modules/k8s_info.py @@ -9,10 +9,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - DOCUMENTATION = ''' module: k8s_info diff --git a/plugins/modules/k8s_log.py b/plugins/modules/k8s_log.py index 02f08640..3a5b38dd 100644 --- a/plugins/modules/k8s_log.py +++ b/plugins/modules/k8s_log.py @@ -9,10 +9,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - DOCUMENTATION = ''' module: k8s_log diff --git a/plugins/modules/k8s_scale.py b/plugins/modules/k8s_scale.py index ad4cbd18..600ce3cc 100644 --- a/plugins/modules/k8s_scale.py +++ b/plugins/modules/k8s_scale.py @@ -9,9 +9,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} DOCUMENTATION = ''' diff --git a/plugins/modules/k8s_service.py b/plugins/modules/k8s_service.py index 97d3ce0c..1366caef 100644 --- a/plugins/modules/k8s_service.py +++ b/plugins/modules/k8s_service.py @@ -9,10 +9,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - DOCUMENTATION = ''' module: k8s_service diff --git a/tests/integration/targets/kubernetes/library/test_tempfile.py b/tests/integration/targets/kubernetes/library/test_tempfile.py index 820f5f59..c56377c0 100644 --- a/tests/integration/targets/kubernetes/library/test_tempfile.py +++ b/tests/integration/targets/kubernetes/library/test_tempfile.py @@ -8,9 +8,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} DOCUMENTATION = ''' --- From 3e60ccacc34320ef51d65c57242ffe83aafa725e Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Thu, 14 May 2020 09:20:00 -0500 Subject: [PATCH 04/88] Fixes #96: Sanity test finds incorrect deprecated usage. --- plugins/modules/k8s_info.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/modules/k8s_info.py b/plugins/modules/k8s_info.py index 442a4209..af394d49 100644 --- a/plugins/modules/k8s_info.py +++ b/plugins/modules/k8s_info.py @@ -143,8 +143,6 @@ class KubernetesInfoModule(KubernetesAnsibleModule): KubernetesAnsibleModule.__init__(self, *args, supports_check_mode=True, **kwargs) - if self._name == 'k8s_facts': - self.deprecate("The 'k8s_facts' module has been renamed to 'k8s_info'", version='2.13') def execute_module(self): self.client = self.get_api_client() From aad3ec7ad59dd89313ae6ad0281b1d5398556244 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Thu, 14 May 2020 09:39:17 -0500 Subject: [PATCH 05/88] Add version_added to docs for each of the new collection modules. --- plugins/modules/helm.py | 2 ++ plugins/modules/helm_info.py | 2 ++ plugins/modules/helm_repository.py | 2 ++ plugins/modules/k8s_exec.py | 2 ++ plugins/modules/k8s_log.py | 2 ++ 5 files changed, 10 insertions(+) diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 0af2b2ea..379f5141 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -13,6 +13,8 @@ module: helm short_description: Manages Kubernetes packages with the Helm package manager +version_added: "0.11.0" + author: - Lucas Boisserie (@LucasBoisserie) - Matthieu Diehr (@d-matt) diff --git a/plugins/modules/helm_info.py b/plugins/modules/helm_info.py index 382623e3..cccbf250 100644 --- a/plugins/modules/helm_info.py +++ b/plugins/modules/helm_info.py @@ -13,6 +13,8 @@ module: helm_info short_description: Get informations from Helm package deployed inside the cluster +version_added: "0.11.0" + author: - Lucas Boisserie (@LucasBoisserie) diff --git a/plugins/modules/helm_repository.py b/plugins/modules/helm_repository.py index 95560933..e097b133 100644 --- a/plugins/modules/helm_repository.py +++ b/plugins/modules/helm_repository.py @@ -13,6 +13,8 @@ module: helm_repository short_description: Add and remove Helm repository +version_added: "0.11.0" + author: - Lucas Boisserie (@LucasBoisserie) diff --git a/plugins/modules/k8s_exec.py b/plugins/modules/k8s_exec.py index 65ceb79d..fe710e9c 100644 --- a/plugins/modules/k8s_exec.py +++ b/plugins/modules/k8s_exec.py @@ -15,6 +15,8 @@ module: k8s_exec short_description: Execute command in Pod +version_added: "0.10.0" + author: "Tristan de Cacqueray (@tristanC)" description: diff --git a/plugins/modules/k8s_log.py b/plugins/modules/k8s_log.py index 3a5b38dd..6f8d5b46 100644 --- a/plugins/modules/k8s_log.py +++ b/plugins/modules/k8s_log.py @@ -14,6 +14,8 @@ module: k8s_log short_description: Fetch logs from Kubernetes resources +version_added: "0.10.0" + author: - "Fabian von Feilitzsch (@fabianvf)" From 35ffd0e4318fd56490df275ec71b48ab2a227cd1 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Tue, 5 May 2020 09:36:46 +1000 Subject: [PATCH 06/88] Improve k8s Deployment and Daemonset wait conditions Ensure that Deployments and Daemonsets properly await all replicas to be available. Correctly handles the subtle edge case when a service account no longer exists. Note that this will dramatically slow Daemonset updates --- README.md | 2 +- molecule/default/molecule.yml | 2 + molecule/default/tasks/apply.yml | 156 +++++++++++++++++++++++++++++++ molecule/default/vars/main.yml | 3 + plugins/module_utils/raw.py | 6 +- plugins/module_utils/scale.py | 30 +++--- 6 files changed, 182 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 65ccc2ba..2f4480f1 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ After the version is published, verify it exists on the [Kubernetes Collection G ## More Information -For more information about Ansible's Kubernetes integration, join the `#ansible-community` channel on Freenode IRC, and browse the resources in the [Kubernetes Working Group](https://github.com/ansible/community/wiki/Kubernetes) Community wiki page. +For more information about Ansible's Kubernetes integration, join the `#ansible-kubernetes` channel on Freenode IRC, and browse the resources in the [Kubernetes Working Group](https://github.com/ansible/community/wiki/Kubernetes) Community wiki page. ## License diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 90ba2e53..37f7c3bc 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -21,6 +21,8 @@ provisioner: ansible_python_interpreter: '{{ ansible_playbook_python }}' env: ANSIBLE_FORCE_COLOR: 'true' + options: + vvv: True scenario: name: default test_sequence: diff --git a/molecule/default/tasks/apply.yml b/molecule/default/tasks/apply.yml index f5362220..0b2de35b 100644 --- a/molecule/default/tasks/apply.yml +++ b/molecule/default/tasks/apply.yml @@ -179,6 +179,162 @@ - k8s_service_3.result.spec.ports | length == 1 - k8s_service_3.result.spec.ports[0].port == 8081 + - name: Insert new service port + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: mesh + port: 8080 + targetPort: 8080 + - name: http + port: 8081 + targetPort: 8081 + apply: yes + register: k8s_service_4 + + - name: Check ports are correct + assert: + that: + - k8s_service_4 is changed + - k8s_service_4.result.spec.ports | length == 2 + - k8s_service_4.result.spec.ports[0].port == 8080 + - k8s_service_4.result.spec.ports[1].port == 8081 + + - name: Remove new service port (check mode) + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: http + port: 8081 + targetPort: 8081 + apply: yes + check_mode: yes + register: k8s_service_check + + - name: Check ports are correct + assert: + that: + - k8s_service_check is changed + - k8s_service_check.result.spec.ports | length == 1 + - k8s_service_check.result.spec.ports[0].port == 8081 + + - name: Remove new service port + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: http + port: 8081 + targetPort: 8081 + apply: yes + register: k8s_service_5 + + - name: Check ports are correct + assert: + that: + - k8s_service_5 is changed + - k8s_service_5.result.spec.ports | length == 1 + - k8s_service_5.result.spec.ports[0].port == 8081 + + - name: Add a serviceaccount + k8s: + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + + - name: Add a deployment + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + apply: yes + vars: + k8s_pod_name: apply-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green + k8s_pod_service_account: apply-deploy + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + + - name: Remove the serviceaccount + k8s: + state: absent + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + + - name: Update the earlier deployment + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + apply: yes + vars: + k8s_pod_name: apply-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple + k8s_pod_service_account: apply-deploy + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + register: deploy_after_serviceaccount_removal + ignore_errors: yes + + - name: Ensure that updating deployment after service account removal failed + assert: + that: + - deploy_after_serviceaccount_removal is failed + always: - name: Remove namespace k8s: diff --git a/molecule/default/vars/main.yml b/molecule/default/vars/main.yml index 8368ae27..2fdaa77f 100644 --- a/molecule/default/vars/main.yml +++ b/molecule/default/vars/main.yml @@ -4,6 +4,7 @@ k8s_pod_metadata: app: "{{ k8s_pod_name }}" k8s_pod_spec: + serviceAccount: "{{ k8s_pod_service_account }}" containers: - image: "{{ k8s_pod_image }}" imagePullPolicy: Always @@ -20,6 +21,8 @@ k8s_pod_spec: memory: "100Mi" ports: "{{ k8s_pod_ports }}" +k8s_pod_service_account: default + k8s_pod_command: [] k8s_pod_ports: [] diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index de214e90..828df558 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -469,7 +469,8 @@ class KubernetesRawModule(KubernetesAnsibleModule): # Furthermore deployment.status.availableReplicas == deployment.status.replicas == None if status is empty return (deployment.status and deployment.status.replicas is not None and deployment.status.availableReplicas == deployment.status.replicas and - deployment.status.observedGeneration == deployment.metadata.generation) + deployment.status.observedGeneration == deployment.metadata.generation and + not deployment.status.unavailableReplicas) def _pod_ready(pod): return (pod.status and pod.status.containerStatuses is not None and @@ -478,7 +479,8 @@ class KubernetesRawModule(KubernetesAnsibleModule): def _daemonset_ready(daemonset): return (daemonset.status and daemonset.status.desiredNumberScheduled is not None and daemonset.status.numberReady == daemonset.status.desiredNumberScheduled and - daemonset.status.observedGeneration == daemonset.metadata.generation) + daemonset.status.observedGeneration == daemonset.metadata.generation and + not daemonset.status.unavailableReplicas) def _custom_condition(resource): if not resource.status or not resource.status.conditions: diff --git a/plugins/module_utils/scale.py b/plugins/module_utils/scale.py index 4b798bb2..1c153952 100644 --- a/plugins/module_utils/scale.py +++ b/plugins/module_utils/scale.py @@ -29,11 +29,16 @@ from ansible.module_utils.six import string_types try: import yaml - from openshift import watch from openshift.dynamic.client import ResourceInstance - from openshift.helper.exceptions import KubernetesException -except ImportError as exc: - class KubernetesException(Exception): + from openshift.dynamic.exceptions import NotFoundError +except ImportError: + pass +try: + from openshift import watch +except ImportError: + try: + from openshift.dynamic.client import watch + except ImportError: pass @@ -114,7 +119,7 @@ class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): try: existing = resource.get(name=name, namespace=namespace) return_attributes['result'] = existing.to_dict() - except KubernetesException as exc: + except NotFoundError as exc: self.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc), error=exc.value.get('status')) @@ -189,15 +194,12 @@ class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): """ Create a stream of events for the object """ w = None stream = None - try: - w = watch.Watch() - w._api_client = self.client.client - if namespace: - stream = w.stream(resource.get, serialize=False, namespace=namespace, timeout_seconds=wait_time) - else: - stream = w.stream(resource.get, serialize=False, namespace=namespace, timeout_seconds=wait_time) - except KubernetesException: - pass + w = watch.Watch() + w._api_client = self.client.client + if namespace: + stream = w.stream(resource.get, serialize=False, namespace=namespace, timeout_seconds=wait_time) + else: + stream = w.stream(resource.get, serialize=False, namespace=namespace, timeout_seconds=wait_time) return w, stream def _read_stream(self, resource, watcher, stream, name, replicas): From e7736cb12d225b7aab02b5669d4ae9346382fcba Mon Sep 17 00:00:00 2001 From: Will Thames Date: Tue, 19 May 2020 18:13:18 +1000 Subject: [PATCH 07/88] Don't run project coverage on patches Coverage improvement for the project is not a requirement of the collections projects. Don't fail builds on coverage reduction --- codecov.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codecov.yml b/codecov.yml index 33c8f6ee..71e957c6 100644 --- a/codecov.yml +++ b/codecov.yml @@ -3,3 +3,6 @@ coverage: precision: 2 round: down range: "70...100" + status: + project: + default: false From d9ece473dda4e4703b54f7b568bc2139087ddee2 Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Wed, 20 May 2020 07:48:35 -0700 Subject: [PATCH 08/88] Fix the docs for the inventory plugins. Documenting the structure of the dictionary to pass in needs to be done via suboptions rather than putting the structure directoly inside of the toplevel option. --- plugins/inventory/k8s.py | 109 +++++++++++++++++---------------- plugins/inventory/openshift.py | 109 +++++++++++++++++---------------- 2 files changed, 110 insertions(+), 108 deletions(-) diff --git a/plugins/inventory/k8s.py b/plugins/inventory/k8s.py index 6f845c4e..d371b65c 100644 --- a/plugins/inventory/k8s.py +++ b/plugins/inventory/k8s.py @@ -28,60 +28,61 @@ DOCUMENTATION = ''' - Optional list of cluster connection settings. If no connections are provided, the default I(~/.kube/config) and active context will be used, and objects will be returned for all namespaces the active user is authorized to access. - name: - description: - - Optional name to assign to the cluster. If not provided, a name is constructed from the server - and port. - 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 - environment variable. - context: - description: - - The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment - variable. - host: - description: - - Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable. - api_key: - description: - - Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment - variable. - username: - description: - - Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME - environment variable. - password: - description: - - Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD - environment variable. - client_cert: - description: - - Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE - environment variable. - aliases: [ cert_file ] - client_key: - description: - - Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_KEY_FILE - environment variable. - aliases: [ key_file ] - ca_cert: - description: - - Path to a CA certificate used to authenticate with the API. Can also be specified via - K8S_AUTH_SSL_CA_CERT environment variable. - aliases: [ ssl_ca_cert ] - validate_certs: - description: - - "Whether or not to verify the API server's SSL certificates. Can also be specified via - K8S_AUTH_VERIFY_SSL environment variable." - type: bool - aliases: [ verify_ssl ] - namespaces: - description: - - List of namespaces. If not specified, will fetch all containers for all namespaces user is authorized - to access. + suboptions: + name: + description: + - Optional name to assign to the cluster. If not provided, a name is constructed from the server + and port. + 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 + environment variable. + context: + description: + - The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment + variable. + host: + description: + - Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable. + api_key: + description: + - Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment + variable. + username: + description: + - Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME + environment variable. + password: + description: + - Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD + environment variable. + client_cert: + description: + - Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE + environment variable. + aliases: [ cert_file ] + client_key: + description: + - Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_KEY_FILE + environment variable. + aliases: [ key_file ] + ca_cert: + description: + - Path to a CA certificate used to authenticate with the API. Can also be specified via + K8S_AUTH_SSL_CA_CERT environment variable. + aliases: [ ssl_ca_cert ] + validate_certs: + description: + - "Whether or not to verify the API server's SSL certificates. Can also be specified via + K8S_AUTH_VERIFY_SSL environment variable." + type: bool + aliases: [ verify_ssl ] + namespaces: + description: + - List of namespaces. If not specified, will fetch all containers for all namespaces user is authorized + to access. requirements: - "python >= 2.7" diff --git a/plugins/inventory/openshift.py b/plugins/inventory/openshift.py index ddee2836..bdd63406 100644 --- a/plugins/inventory/openshift.py +++ b/plugins/inventory/openshift.py @@ -28,60 +28,61 @@ DOCUMENTATION = ''' - Optional list of cluster connection settings. If no connections are provided, the default I(~/.kube/config) and active context will be used, and objects will be returned for all namespaces the active user is authorized to access. - name: - description: - - Optional name to assign to the cluster. If not provided, a name is constructed from the server - and port. - 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 - environment variable. - context: - description: - - The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment - variable. - host: - description: - - Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable. - api_key: - description: - - Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment - variable. - username: - description: - - Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME - environment variable. - password: - description: - - Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD - environment variable. - client_cert: - description: - - Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE - environment variable. - aliases: [ cert_file ] - client_key: - description: - - Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_KEY_FILE - environment variable. - aliases: [ key_file ] - ca_cert: - description: - - Path to a CA certificate used to authenticate with the API. Can also be specified via - K8S_AUTH_SSL_CA_CERT environment variable. - aliases: [ ssl_ca_cert ] - validate_certs: - description: - - "Whether or not to verify the API server's SSL certificates. Can also be specified via - K8S_AUTH_VERIFY_SSL environment variable." - type: bool - aliases: [ verify_ssl ] - namespaces: - description: - - List of namespaces. If not specified, will fetch all containers for all namespaces user is authorized - to access. + suboptions: + name: + description: + - Optional name to assign to the cluster. If not provided, a name is constructed from the server + and port. + 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 + environment variable. + context: + description: + - The name of a context found in the config file. Can also be specified via K8S_AUTH_CONTEXT environment + variable. + host: + description: + - Provide a URL for accessing the API. Can also be specified via K8S_AUTH_HOST environment variable. + api_key: + description: + - Token used to authenticate with the API. Can also be specified via K8S_AUTH_API_KEY environment + variable. + username: + description: + - Provide a username for authenticating with the API. Can also be specified via K8S_AUTH_USERNAME + environment variable. + password: + description: + - Provide a password for authenticating with the API. Can also be specified via K8S_AUTH_PASSWORD + environment variable. + client_cert: + description: + - Path to a certificate used to authenticate with the API. Can also be specified via K8S_AUTH_CERT_FILE + environment variable. + aliases: [ cert_file ] + client_key: + description: + - Path to a key file used to authenticate with the API. Can also be specified via K8S_AUTH_KEY_FILE + environment variable. + aliases: [ key_file ] + ca_cert: + description: + - Path to a CA certificate used to authenticate with the API. Can also be specified via + K8S_AUTH_SSL_CA_CERT environment variable. + aliases: [ ssl_ca_cert ] + validate_certs: + description: + - "Whether or not to verify the API server's SSL certificates. Can also be specified via + K8S_AUTH_VERIFY_SSL environment variable." + type: bool + aliases: [ verify_ssl ] + namespaces: + description: + - List of namespaces. If not specified, will fetch all containers for all namespaces user is authorized + to access. requirements: - "python >= 2.7" From 00200cf917dbdd4340d0e0493b8fae4552a28237 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Thu, 21 May 2020 12:39:04 +1000 Subject: [PATCH 09/88] Add test for openshift apply bug Fails using 0.11.0 --- molecule/default/tasks/apply.yml | 64 ++++++++++++++++++++++++++----- molecule/default/tasks/waiter.yml | 6 +++ molecule/default/vars/main.yml | 11 ++++-- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/molecule/default/tasks/apply.yml b/molecule/default/tasks/apply.yml index d47ed276..1dd49e17 100644 --- a/molecule/default/tasks/apply.yml +++ b/molecule/default/tasks/apply.yml @@ -316,16 +316,13 @@ - containerPort: 8080 name: http protocol: TCP - - - name: Remove the serviceaccount - k8s: - state: absent - definition: - apiVersion: v1 - kind: ServiceAccount - metadata: - name: apply-deploy - namespace: "{{ apply_namespace }}" + k8s_pod_resources: + requests: + cpu: 100m + memory: 100Mi + limits: + cpu: 100m + memory: 100Mi - name: Update the earlier deployment k8s: @@ -351,6 +348,53 @@ - containerPort: 8080 name: http protocol: TCP + k8s_pod_resources: + requests: + cpu: 50m + limits: + cpu: 50m + memory: 50Mi + + - name: Remove the serviceaccount + k8s: + state: absent + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + + - name: Apply deployment after service account removed + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + apply: yes + vars: + k8s_pod_name: apply-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green + k8s_pod_service_account: apply-deploy + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + k8s_pod_resources: + requests: + cpu: 50m + limits: + cpu: 50m + memory: 50Mi register: deploy_after_serviceaccount_removal ignore_errors: yes diff --git a/molecule/default/tasks/waiter.yml b/molecule/default/tasks/waiter.yml index 98ee6416..92d1adc7 100644 --- a/molecule/default/tasks/waiter.yml +++ b/molecule/default/tasks/waiter.yml @@ -229,6 +229,12 @@ protocol: TCP register: update_deploy + # It looks like the Deployment is updated to have the desired state *before* the pods are terminated + # Wait a couple of seconds to allow the old pods to at least get to Terminating state + - name: Avoid race condition + pause: + seconds: 2 + - name: Get updated pods k8s_info: api_version: v1 diff --git a/molecule/default/vars/main.yml b/molecule/default/vars/main.yml index 2fdaa77f..069a0139 100644 --- a/molecule/default/vars/main.yml +++ b/molecule/default/vars/main.yml @@ -15,14 +15,17 @@ k8s_pod_spec: exec: command: - /bin/true - resources: - limits: - cpu: "100m" - memory: "100Mi" + resources: "{{ k8s_pod_resources }}" ports: "{{ k8s_pod_ports }}" + k8s_pod_service_account: default +k8s_pod_resources: + limits: + cpu: "100m" + memory: "100Mi" + k8s_pod_command: [] k8s_pod_ports: [] From beebe98ce63f295f63e1e9e767922584d3816cb4 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Fri, 22 May 2020 12:39:43 +1000 Subject: [PATCH 10/88] Fix scale wait and add tests Move wait logic out of raw and into common and use that logic in scale Fix a few broken wait condition cases highlighted by scaling up and down Move scale-related tests into dedicated test task file Additional service related tests --- molecule/default/converge.yml | 1 + molecule/default/tasks/apply.yml | 156 ++++++++++++++++++++++ molecule/default/tasks/scale.yml | 214 +++++++++++++++++++++++++++++++ plugins/module_utils/common.py | 92 ++++++++++++- plugins/module_utils/raw.py | 84 ------------ plugins/module_utils/scale.py | 104 +++------------ plugins/modules/k8s_scale.py | 5 + 7 files changed, 486 insertions(+), 170 deletions(-) create mode 100644 molecule/default/tasks/scale.yml diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index ebac0811..68dd56b3 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -21,6 +21,7 @@ that: (pod_list.resources | count) > 5 - include_tasks: tasks/delete.yml + - include_tasks: tasks/scale.yml - include_tasks: tasks/apply.yml - include_tasks: tasks/waiter.yml - include_tasks: tasks/full.yml diff --git a/molecule/default/tasks/apply.yml b/molecule/default/tasks/apply.yml index 1dd49e17..b3637bd7 100644 --- a/molecule/default/tasks/apply.yml +++ b/molecule/default/tasks/apply.yml @@ -403,6 +403,162 @@ that: - deploy_after_serviceaccount_removal is failed + - name: Insert new service port + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: mesh + port: 8080 + targetPort: 8080 + - name: http + port: 8081 + targetPort: 8081 + apply: yes + register: k8s_service_4 + + - name: Check ports are correct + assert: + that: + - k8s_service_4 is changed + - k8s_service_4.result.spec.ports | length == 2 + - k8s_service_4.result.spec.ports[0].port == 8080 + - k8s_service_4.result.spec.ports[1].port == 8081 + + - name: Remove new service port (check mode) + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: http + port: 8081 + targetPort: 8081 + apply: yes + check_mode: yes + register: k8s_service_check + + - name: Check ports are correct + assert: + that: + - k8s_service_check is changed + - k8s_service_check.result.spec.ports | length == 1 + - k8s_service_check.result.spec.ports[0].port == 8081 + + - name: Remove new service port + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: http + port: 8081 + targetPort: 8081 + apply: yes + register: k8s_service_5 + + - name: Check ports are correct + assert: + that: + - k8s_service_5 is changed + - k8s_service_5.result.spec.ports | length == 1 + - k8s_service_5.result.spec.ports[0].port == 8081 + + - name: Add a serviceaccount + k8s: + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + + - name: Add a deployment + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + apply: yes + vars: + k8s_pod_name: apply-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green + k8s_pod_service_account: apply-deploy + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + + - name: Remove the serviceaccount + k8s: + state: absent + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + + - name: Update the earlier deployment + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + spec: + replicas: 2 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + apply: yes + vars: + k8s_pod_name: apply-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple + k8s_pod_service_account: apply-deploy + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + register: deploy_after_serviceaccount_removal + ignore_errors: yes + + - name: Ensure that updating deployment after service account removal failed + assert: + that: + - deploy_after_serviceaccount_removal is failed + always: - name: Remove namespace k8s: diff --git a/molecule/default/tasks/scale.yml b/molecule/default/tasks/scale.yml new file mode 100644 index 00000000..686562da --- /dev/null +++ b/molecule/default/tasks/scale.yml @@ -0,0 +1,214 @@ +--- +- block: + - set_fact: + scale_namespace: scale + + - name: Ensure namespace exists + k8s: + definition: + apiVersion: v1 + kind: Namespace + metadata: + name: "{{ scale_namespace }}" + + - name: Add a deployment + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: scale-deploy + namespace: "{{ scale_namespace }}" + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + wait_timeout: 60 + apply: yes + vars: + k8s_pod_name: scale-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + + - name: Get pods in scale-deploy + k8s_info: + kind: Pod + label_selectors: + - app=scale-deploy + namespace: "{{ scale_namespace }}" + field_selectors: + - status.phase=Running + + - name: Scale the deployment + k8s_scale: + api_version: apps/v1 + kind: Deployment + name: scale-deploy + namespace: "{{ scale_namespace }}" + replicas: 0 + wait: yes + register: scale_down + + # It looks like the Deployment is updated to have the desired state *before* the pods are terminated + # Wait a couple of seconds to allow the pods to at least get to Terminating state + - name: Avoid race condition + pause: + seconds: 2 + + - name: Get pods in scale-deploy + k8s_info: + kind: Pod + label_selectors: + - app=scale-deploy + namespace: "{{ scale_namespace }}" + field_selectors: + - status.phase=Running + register: scale_down_deploy_pods + + - name: Ensure that scale down took effect + assert: + that: + - scale_down is changed + - '"duration" in scale_down' + - scale_down.diff + - scale_down_deploy_pods.resources | length == 0 + + - name: Reapply the earlier deployment + k8s: + definition: + api_version: apps/v1 + kind: Deployment + metadata: + name: scale-deploy + namespace: "{{ scale_namespace }}" + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + wait_timeout: 60 + apply: yes + vars: + k8s_pod_name: scale-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + register: reapply_after_scale + + - name: Get pods in scale-deploy + k8s_info: + kind: Pod + label_selectors: + - app=scale-deploy + namespace: "{{ scale_namespace }}" + field_selectors: + - status.phase=Running + register: scale_up_deploy_pods + + - name: Ensure that reapply after scale worked + assert: + that: + - reapply_after_scale is changed + - scale_up_deploy_pods.resources | length == 1 + + - name: Scale the deployment up + k8s_scale: + api_version: apps/v1 + kind: Deployment + name: scale-deploy + namespace: "{{ scale_namespace }}" + replicas: 2 + wait: yes + wait_timeout: 60 + register: scale_up + + - name: Get pods in scale-deploy + k8s_info: + kind: Pod + label_selectors: + - app=scale-deploy + field_selectors: + - status.phase=Running + namespace: "{{ scale_namespace }}" + register: scale_up_further_deploy_pods + + - name: Ensure that scale up worked + assert: + that: + - scale_up is changed + - '"duration" in scale_up' + - scale_up.diff + - scale_up_further_deploy_pods.resources | length == 2 + + - name: Don't scale the deployment up + k8s_scale: + api_version: apps/v1 + kind: Deployment + name: scale-deploy + namespace: "{{ scale_namespace }}" + replicas: 2 + wait: yes + register: scale_up_noop + + - name: Get pods in scale-deploy + k8s_info: + kind: Pod + label_selectors: + - app=scale-deploy + field_selectors: + - status.phase=Running + namespace: "{{ scale_namespace }}" + register: scale_up_noop_pods + + - name: Ensure that no-op scale up worked + assert: + that: + - scale_up_noop is not changed + - not scale_up_noop.diff + - scale_up_noop_pods.resources | length == 2 + - '"duration" in scale_up_noop' + + - name: Scale deployment down without wait + k8s_scale: + api_version: apps/v1 + kind: Deployment + name: scale-deploy + namespace: "{{ scale_namespace }}" + replicas: 1 + wait: no + register: scale_down_no_wait + + - name: Ensure that scale down succeeds + k8s_info: + kind: Pod + label_selectors: + - app=scale-deploy + namespace: "{{ scale_namespace }}" + register: scale_down_no_wait_pods + retries: 6 + delay: 5 + until: "{{ scale_down_no_wait_pods.resources | length == 1 }}" + + - name: Ensure that scale down without wait worked + assert: + that: + - scale_down_no_wait is changed + - scale_down_no_wait.diff + - scale_down_no_wait_pods.resources | length == 1 + + always: + - name: Remove namespace + k8s: + kind: Namespace + name: "{{ scale_namespace }}" + state: absent diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 7c88f5be..f9562011 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -19,7 +19,8 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type import copy -import json +from datetime import datetime +import time import os import traceback @@ -34,7 +35,7 @@ try: import kubernetes import openshift from openshift.dynamic import DynamicClient - from openshift.dynamic.exceptions import ResourceNotFoundError, ResourceNotUniqueError + from openshift.dynamic.exceptions import ResourceNotFoundError, ResourceNotUniqueError, NotFoundError HAS_K8S_MODULE_HELPER = True k8s_import_exception = None except ImportError as e: @@ -291,3 +292,90 @@ class KubernetesAnsibleModule(AnsibleModule, K8sAnsibleMixin): def fail(self, msg=None): self.fail_json(msg=msg) + + def _wait_for(self, resource, name, namespace, predicate, sleep, timeout, state): + start = datetime.now() + + def _wait_for_elapsed(): + return (datetime.now() - start).seconds + + response = None + while _wait_for_elapsed() < timeout: + try: + response = resource.get(name=name, namespace=namespace) + if predicate(response): + if response: + return True, response.to_dict(), _wait_for_elapsed() + else: + return True, {}, _wait_for_elapsed() + time.sleep(sleep) + except NotFoundError: + if state == 'absent': + return True, {}, _wait_for_elapsed() + if response: + response = response.to_dict() + return False, response, _wait_for_elapsed() + + def wait(self, resource, definition, sleep, timeout, state='present', condition=None): + + def _deployment_ready(deployment): + # FIXME: frustratingly bool(deployment.status) is True even if status is empty + # Furthermore deployment.status.availableReplicas == deployment.status.replicas == None if status is empty + # deployment.status.replicas is None is perfectly ok if desired replicas == 0 + # Scaling up means that we also need to check that we're not in a + # situation where status.replicas == status.availableReplicas + # but spec.replicas != status.replicas + return (deployment.status and + deployment.spec.replicas == (deployment.status.replicas or 0) and + deployment.status.availableReplicas == deployment.status.replicas and + deployment.status.observedGeneration == deployment.metadata.generation and + not deployment.status.unavailableReplicas) + + def _pod_ready(pod): + return (pod.status and pod.status.containerStatuses is not None and + all([container.ready for container in pod.status.containerStatuses])) + + def _daemonset_ready(daemonset): + return (daemonset.status and daemonset.status.desiredNumberScheduled is not None and + daemonset.status.numberReady == daemonset.status.desiredNumberScheduled and + daemonset.status.observedGeneration == daemonset.metadata.generation and + not daemonset.status.unavailableReplicas) + + def _custom_condition(resource): + if not resource.status or not resource.status.conditions: + return False + match = [x for x in resource.status.conditions if x.type == condition['type']] + if not match: + return False + # There should never be more than one condition of a specific type + match = match[0] + if match.status == 'Unknown': + if match.status == condition['status']: + if 'reason' not in condition: + return True + if condition['reason']: + return match.reason == condition['reason'] + return False + status = True if match.status == 'True' else False + if status == condition['status']: + if condition.get('reason'): + return match.reason == condition['reason'] + return True + return False + + def _resource_absent(resource): + return not resource + + waiter = dict( + Deployment=_deployment_ready, + DaemonSet=_daemonset_ready, + Pod=_pod_ready + ) + kind = definition['kind'] + if state == 'present' and not condition: + predicate = waiter.get(kind, lambda x: x) + elif state == 'present' and condition: + predicate = _custom_condition + else: + predicate = _resource_absent + return self._wait_for(resource, definition['metadata']['name'], definition['metadata'].get('namespace'), predicate, sleep, timeout, state) diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index 16dafaab..775deef7 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -20,9 +20,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type import copy -from datetime import datetime from distutils.version import LooseVersion -import time import sys import traceback @@ -442,85 +440,3 @@ class KubernetesRawModule(KubernetesAnsibleModule): result['changed'] = True result['method'] = 'create' return result - - def _wait_for(self, resource, name, namespace, predicate, sleep, timeout, state): - start = datetime.now() - - def _wait_for_elapsed(): - return (datetime.now() - start).seconds - - response = None - while _wait_for_elapsed() < timeout: - try: - response = resource.get(name=name, namespace=namespace) - if predicate(response): - if response: - return True, response.to_dict(), _wait_for_elapsed() - else: - return True, {}, _wait_for_elapsed() - time.sleep(sleep) - except NotFoundError: - if state == 'absent': - return True, {}, _wait_for_elapsed() - if response: - response = response.to_dict() - return False, response, _wait_for_elapsed() - - def wait(self, resource, definition, sleep, timeout, state='present', condition=None): - - def _deployment_ready(deployment): - # FIXME: frustratingly bool(deployment.status) is True even if status is empty - # Furthermore deployment.status.availableReplicas == deployment.status.replicas == None if status is empty - return (deployment.status and deployment.status.replicas is not None and - deployment.status.availableReplicas == deployment.status.replicas and - deployment.status.observedGeneration == deployment.metadata.generation and - not deployment.status.unavailableReplicas) - - def _pod_ready(pod): - return (pod.status and pod.status.containerStatuses is not None and - all([container.ready for container in pod.status.containerStatuses])) - - def _daemonset_ready(daemonset): - return (daemonset.status and daemonset.status.desiredNumberScheduled is not None and - daemonset.status.numberReady == daemonset.status.desiredNumberScheduled and - daemonset.status.observedGeneration == daemonset.metadata.generation and - not daemonset.status.unavailableReplicas) - - def _custom_condition(resource): - if not resource.status or not resource.status.conditions: - return False - match = [x for x in resource.status.conditions if x.type == condition['type']] - if not match: - return False - # There should never be more than one condition of a specific type - match = match[0] - if match.status == 'Unknown': - if match.status == condition['status']: - if 'reason' not in condition: - return True - if condition['reason']: - return match.reason == condition['reason'] - return False - status = True if match.status == 'True' else False - if status == condition['status']: - if condition.get('reason'): - return match.reason == condition['reason'] - return True - return False - - def _resource_absent(resource): - return not resource - - waiter = dict( - Deployment=_deployment_ready, - DaemonSet=_daemonset_ready, - Pod=_pod_ready - ) - kind = definition['kind'] - if state == 'present' and not condition: - predicate = waiter.get(kind, lambda x: x) - elif state == 'present' and condition: - predicate = _custom_condition - else: - predicate = _resource_absent - return self._wait_for(resource, definition['metadata']['name'], definition['metadata'].get('namespace'), predicate, sleep, timeout, state) diff --git a/plugins/module_utils/scale.py b/plugins/module_utils/scale.py index 1c153952..27f1abe0 100644 --- a/plugins/module_utils/scale.py +++ b/plugins/module_utils/scale.py @@ -20,8 +20,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type import copy -import math -import time from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule @@ -29,17 +27,9 @@ from ansible.module_utils.six import string_types try: import yaml - from openshift.dynamic.client import ResourceInstance from openshift.dynamic.exceptions import NotFoundError except ImportError: pass -try: - from openshift import watch -except ImportError: - try: - from openshift.dynamic.client import watch - except ImportError: - pass SCALE_ARG_SPEC = { @@ -112,7 +102,9 @@ class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): wait_time = self.params.get('wait_timeout') existing = None existing_count = None - return_attributes = dict(changed=False, result=dict()) + return_attributes = dict(changed=False, result=dict(), diff=dict()) + if wait: + return_attributes['duration'] = 0 resource = self.find_resource(kind, api_version, fail=True) @@ -142,10 +134,9 @@ class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): if not self.check_mode: if self.kind == 'job': existing.spec.parallelism = replicas - k8s_obj = resource.patch(existing.to_dict()) + return_attributes['result'] = resource.patch(existing.to_dict()).to_dict() else: - k8s_obj = self.scale(resource, existing, replicas, wait, wait_time) - return_attributes['result'] = k8s_obj.to_dict() + return_attributes = self.scale(resource, existing, replicas, wait, wait_time) self.exit_json(**return_attributes) @@ -161,86 +152,31 @@ class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): def scale(self, resource, existing_object, replicas, wait, wait_time): name = existing_object.metadata.name namespace = existing_object.metadata.namespace + kind = existing_object.kind if not hasattr(resource, 'scale'): self.fail_json( msg="Cannot perform scale on resource of kind {0}".format(resource.kind) ) - scale_obj = {'metadata': {'name': name, 'namespace': namespace}, 'spec': {'replicas': replicas}} + scale_obj = {'kind': kind, 'metadata': {'name': name, 'namespace': namespace}, 'spec': {'replicas': replicas}} - return_obj = None - stream = None - - if wait: - w, stream = self._create_stream(resource, namespace, wait_time) + existing = resource.get(name=name, namespace=namespace) try: resource.scale.patch(body=scale_obj) except Exception as exc: - self.fail_json( - msg="Scale request failed: {0}".format(exc) - ) + self.fail_json(msg="Scale request failed: {0}".format(exc)) - if wait and stream is not None: - return_obj = self._read_stream(resource, w, stream, name, replicas) + k8s_obj = resource.get(name=name, namespace=namespace).to_dict() + match, diffs = self.diff_objects(existing.to_dict(), k8s_obj) + result = dict() + result['result'] = k8s_obj + result['changed'] = not match + result['diff'] = diffs - if not return_obj: - return_obj = self._wait_for_response(resource, name, namespace) - - return return_obj - - def _create_stream(self, resource, namespace, wait_time): - """ Create a stream of events for the object """ - w = None - stream = None - w = watch.Watch() - w._api_client = self.client.client - if namespace: - stream = w.stream(resource.get, serialize=False, namespace=namespace, timeout_seconds=wait_time) - else: - stream = w.stream(resource.get, serialize=False, namespace=namespace, timeout_seconds=wait_time) - return w, stream - - def _read_stream(self, resource, watcher, stream, name, replicas): - """ Wait for ready_replicas to equal the requested number of replicas. """ - return_obj = None - try: - for event in stream: - if event.get('object'): - obj = ResourceInstance(resource, event['object']) - if obj.metadata.name == name and hasattr(obj, 'status'): - if replicas == 0: - if not hasattr(obj.status, 'readyReplicas') or not obj.status.readyReplicas: - return_obj = obj - watcher.stop() - break - if hasattr(obj.status, 'readyReplicas') and obj.status.readyReplicas == replicas: - return_obj = obj - watcher.stop() - break - except Exception as exc: - self.fail_json(msg="Exception reading event stream: {0}".format(exc)) - - if not return_obj: - self.fail_json(msg="Error fetching the patched object. Try a higher wait_timeout value.") - if replicas and return_obj.status.readyReplicas is None: - self.fail_json(msg="Failed to fetch the number of ready replicas. Try a higher wait_timeout value.") - if replicas and return_obj.status.readyReplicas != replicas: - self.fail_json(msg="Number of ready replicas is {0}. Failed to reach {1} ready replicas within " - "the wait_timeout period.".format(return_obj.status.ready_replicas, replicas)) - return return_obj - - def _wait_for_response(self, resource, name, namespace): - """ Wait for an API response """ - tries = 0 - half = math.ceil(20 / 2) - obj = None - - while tries <= half: - obj = resource.get(name=name, namespace=namespace) - if obj: - break - tries += 2 - time.sleep(2) - return obj + if wait: + success, result['result'], result['duration'] = self.wait(resource, scale_obj, 5, wait_time) + if not success: + self.fail_json(msg="Resource scaling timed out", **result) + return result diff --git a/plugins/modules/k8s_scale.py b/plugins/modules/k8s_scale.py index 600ce3cc..cf3a0c39 100644 --- a/plugins/modules/k8s_scale.py +++ b/plugins/modules/k8s_scale.py @@ -111,6 +111,11 @@ result: description: Current status details for the object. returned: success type: complex + duration: + description: elapsed time of task in seconds + returned: when C(wait) is true + type: int + sample: 48 ''' from ansible_collections.community.kubernetes.plugins.module_utils.scale import KubernetesAnsibleScaleModule From 5aed26690d7357bc095eaf1df06f6bfae0d76c22 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Fri, 22 May 2020 13:10:12 +1000 Subject: [PATCH 11/88] Update setup-kind action to 0.4.0 See https://github.com/engineerd/setup-kind/releases/tag/v0.4.0 for details of the EXDEV issue --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3fe7c20..9c47af11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,7 @@ jobs: path: ansible_collections/community/kubernetes - name: Set up KinD cluster - uses: engineerd/setup-kind@v0.3.0 + uses: engineerd/setup-kind@v0.4.0 - name: Set up Python ${{ matrix.python_version }} uses: actions/setup-python@v1 From aa70416ae7f9d53bc977ba4ad8223fed0c1351a6 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Fri, 29 May 2020 22:50:28 +1000 Subject: [PATCH 12/88] Fix scale wait and add tests Move wait logic out of raw and into common and use that logic in scale Fix a few broken wait condition cases highlighted by scaling up and down Move scale-related tests into dedicated test task file Additional service related tests --- molecule/default/tasks/apply.yml | 156 ++++++++++++++++++++++++++++++ molecule/default/tasks/scale.yml | 10 +- molecule/default/tasks/waiter.yml | 8 +- 3 files changed, 166 insertions(+), 8 deletions(-) diff --git a/molecule/default/tasks/apply.yml b/molecule/default/tasks/apply.yml index b3637bd7..ca4fa284 100644 --- a/molecule/default/tasks/apply.yml +++ b/molecule/default/tasks/apply.yml @@ -559,6 +559,162 @@ that: - deploy_after_serviceaccount_removal is failed + - name: Insert new service port + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: mesh + port: 8080 + targetPort: 8080 + - name: http + port: 8081 + targetPort: 8081 + apply: yes + register: k8s_service_4 + + - name: Check ports are correct + assert: + that: + - k8s_service_4 is changed + - k8s_service_4.result.spec.ports | length == 2 + - k8s_service_4.result.spec.ports[0].port == 8080 + - k8s_service_4.result.spec.ports[1].port == 8081 + + - name: Remove new service port (check mode) + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: http + port: 8081 + targetPort: 8081 + apply: yes + check_mode: yes + register: k8s_service_check + + - name: Check ports are correct + assert: + that: + - k8s_service_check is changed + - k8s_service_check.result.spec.ports | length == 1 + - k8s_service_check.result.spec.ports[0].port == 8081 + + - name: Remove new service port + k8s: + definition: + apiVersion: v1 + kind: Service + metadata: + name: apply-svc + namespace: "{{ apply_namespace }}" + spec: + selector: + app: whatever + ports: + - name: http + port: 8081 + targetPort: 8081 + apply: yes + register: k8s_service_5 + + - name: Check ports are correct + assert: + that: + - k8s_service_5 is changed + - k8s_service_5.result.spec.ports | length == 1 + - k8s_service_5.result.spec.ports[0].port == 8081 + + - name: Add a serviceaccount + k8s: + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + + - name: Add a deployment + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + apply: yes + vars: + k8s_pod_name: apply-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green + k8s_pod_service_account: apply-deploy + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + + - name: Remove the serviceaccount + k8s: + state: absent + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + + - name: Update the earlier deployment + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + spec: + replicas: 2 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + apply: yes + vars: + k8s_pod_name: apply-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple + k8s_pod_service_account: apply-deploy + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + register: deploy_after_serviceaccount_removal + ignore_errors: yes + + - name: Ensure that updating deployment after service account removal failed + assert: + that: + - deploy_after_serviceaccount_removal is failed + always: - name: Remove namespace k8s: diff --git a/molecule/default/tasks/scale.yml b/molecule/default/tasks/scale.yml index 686562da..32b718df 100644 --- a/molecule/default/tasks/scale.yml +++ b/molecule/default/tasks/scale.yml @@ -55,12 +55,6 @@ wait: yes register: scale_down - # It looks like the Deployment is updated to have the desired state *before* the pods are terminated - # Wait a couple of seconds to allow the pods to at least get to Terminating state - - name: Avoid race condition - pause: - seconds: 2 - - name: Get pods in scale-deploy k8s_info: kind: Pod @@ -70,6 +64,9 @@ field_selectors: - status.phase=Running register: scale_down_deploy_pods + until: "{{ scale_down_deploy_pods.resources | length == 0 }}" + retries: 6 + delay: 5 - name: Ensure that scale down took effect assert: @@ -77,7 +74,6 @@ - scale_down is changed - '"duration" in scale_down' - scale_down.diff - - scale_down_deploy_pods.resources | length == 0 - name: Reapply the earlier deployment k8s: diff --git a/molecule/default/tasks/waiter.yml b/molecule/default/tasks/waiter.yml index 92d1adc7..5434e967 100644 --- a/molecule/default/tasks/waiter.yml +++ b/molecule/default/tasks/waiter.yml @@ -119,6 +119,8 @@ namespace: "{{ wait_namespace }}" label_selectors: - app=wait-ds + field_selectors: + - status.phase=Running register: updated_ds_pods - name: Check that daemonset wait worked @@ -242,13 +244,17 @@ namespace: "{{ wait_namespace }}" label_selectors: - app=wait-deploy + field_selectors: + - status.phase=Running register: updated_deploy_pods + until: "{{ updated_deploy_pods.resources[0].spec.containers[0].image.endswith(':2') }}" + retries: 6 + delay: 5 - name: Check that deployment wait worked assert: that: - deploy.result.status.availableReplicas == deploy.result.status.replicas - - updated_deploy_pods.resources[0].spec.containers[0].image.endswith(":2") - name: Pause a deployment k8s: From b46a5ee10e80f478c395ff5bfe9956d165053a1f Mon Sep 17 00:00:00 2001 From: Sloane Hertel Date: Sat, 30 May 2020 07:42:59 -0400 Subject: [PATCH 13/88] Add action groups for playbooks with module_defaults (#107) * Keep backwards compatibility with playbooks using community.kubernetes content with module_defaults groups --- meta/runtime.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 meta/runtime.yml diff --git a/meta/runtime.yml b/meta/runtime.yml new file mode 100644 index 00000000..3d501bae --- /dev/null +++ b/meta/runtime.yml @@ -0,0 +1,13 @@ +--- +action_groups: + k8s: + - k8s + - k8s_auth + - k8s_facts + - k8s_info + - k8s_scale + - k8s_service + +action_groups_redirection: + k8s: + redirect: k8s From 641fbd92f58964c683f67a17574929ff4746a6d3 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 1 Jun 2020 18:55:30 +0530 Subject: [PATCH 14/88] helm: minor code refactoring Signed-off-by: Abhijeet Kasurde --- plugins/modules/helm.py | 115 ++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 47 deletions(-) diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 379f5141..5a5437da 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -244,27 +244,37 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib module = None -# Get Values from deployed release -def get_values(command, release_name): - get_command = command + " get values --output=yaml " + release_name - - rc, out, err = module.run_command(get_command) - +def exec_command(command): + rc, out, err = module.run_command(command) if rc != 0: module.fail_json( msg="Failure when executing Helm command. Exited {0}.\nstdout: {1}\nstderr: {2}".format(rc, out, err), - command=get_command + stdout=out, + stderr=err, + command=command, ) + return rc, out, err + +def get_values(command, release_name): + """ + Get Values from deployed release + """ + + get_command = command + " get values --output=yaml " + release_name + + rc, out, err = exec_command(get_command) # Helm 3 return "null" string when no values are set if out.rstrip("\n") == "null": return {} - else: - return yaml.safe_load(out) + return yaml.safe_load(out) -# Get Release from all deployed releases def get_release(state, release_name): + """ + Get Release from all deployed releases + """ + if state is not None: for release in state: if release['name'] == release_name: @@ -272,17 +282,14 @@ def get_release(state, release_name): return None -# Get Release state from deployed release def get_release_status(command, release_name): + """ + Get Release state from deployed release + """ + list_command = command + " list --output=yaml --filter " + release_name - rc, out, err = module.run_command(list_command) - - if rc != 0: - module.fail_json( - msg="Failure when executing Helm command. Exited {0}.\nstdout: {1}\nstderr: {2}".format(rc, out, err), - command=list_command - ) + rc, out, err = exec_command(list_command) release = get_release(yaml.safe_load(out), release_name) @@ -294,34 +301,29 @@ def get_release_status(command, release_name): return release -# Run Repo update def run_repo_update(command): + """ + Run Repo update + """ repo_update_command = command + " repo update" - - rc, out, err = module.run_command(repo_update_command) - if rc != 0: - module.fail_json( - msg="Failure when executing Helm command. Exited {0}.\nstdout: {1}\nstderr: {2}".format(rc, out, err), - command=repo_update_command - ) + rc, out, err = exec_command(repo_update_command) -# Get chart info def fetch_chart_info(command, chart_ref): + """ + Get chart info + """ inspect_command = command + " show chart " + chart_ref - rc, out, err = module.run_command(inspect_command) - if rc != 0: - module.fail_json( - msg="Failure when executing Helm command. Exited {0}.\nstdout: {1}\nstderr: {2}".format(rc, out, err), - command=inspect_command - ) + rc, out, err = exec_command(inspect_command) return yaml.safe_load(out) -# Install/upgrade/rollback release chart def deploy(command, release_name, release_values, chart_name, wait, wait_timeout, disable_hook, force): + """ + Install/upgrade/rollback release chart + """ deploy_command = command + " upgrade -i" # install/upgrade # Always reset values to keep release_values equal to values released @@ -342,7 +344,13 @@ def deploy(command, release_name, release_values, chart_name, wait, wait_timeout try: import tempfile except ImportError: - module.fail_json(msg=missing_required_lib("tempfile"), exception=traceback.format_exc()) + module.fail_json( + msg=missing_required_lib("tempfile"), + exception=traceback.format_exc(), + stdout='', + stderr='', + command='', + ) fd, path = tempfile.mkstemp(suffix='.yml') with open(path, 'w') as yaml_file: @@ -354,8 +362,11 @@ def deploy(command, release_name, release_values, chart_name, wait, wait_timeout return deploy_command -# Delete release chart def delete(command, release_name, purge, disable_hook): + """ + Delete release chart + """ + delete_command = command + " uninstall " if not purge: @@ -470,20 +481,30 @@ def main(): changed = True if module.check_mode: - module.exit_json(changed=changed) + module.exit_json( + changed=changed, + command=helm_cmd, + stdout='', + stderr='', + ) elif not changed: - module.exit_json(changed=False, status=release_status) - - rc, out, err = module.run_command(helm_cmd) - - if rc != 0: - module.fail_json( - msg="Failure when executing Helm command. Exited {0}.\nstdout: {1}\nstderr: {2}".format(rc, out, err), - command=helm_cmd + module.exit_json( + changed=False, + status=release_status, + stdout='', + stderr='', + command=helm_cmd, ) - module.exit_json(changed=changed, stdout=out, stderr=err, - status=get_release_status(helm_cmd_common, release_name), command=helm_cmd) + rc, out, err = exec_command(helm_cmd) + + module.exit_json( + changed=changed, + stdout=out, + stderr=err, + status=get_release_status(helm_cmd_common, release_name), + command=helm_cmd, + ) if __name__ == '__main__': From 86a2420efdb93ffe612bff0faa4af0a31efac0c8 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 2 Jun 2020 00:48:35 -0500 Subject: [PATCH 15/88] Add helm and extra k8s modules to action_groups config. (#112) --- meta/runtime.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meta/runtime.yml b/meta/runtime.yml index 3d501bae..f36d9560 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,10 +1,16 @@ --- action_groups: + helm: + - helm + - helm_info + - helm_repository k8s: - k8s - k8s_auth + - k8s_exec - k8s_facts - k8s_info + - k8s_log - k8s_scale - k8s_service From 9a952697a23eaeb6b5d1259e7995c32350de9010 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Tue, 2 Jun 2020 11:19:04 +0530 Subject: [PATCH 16/88] Minor documentation fix (#113) Inventory plugin example should read 'api_key' instead of 'token' Fixes: #101 Signed-off-by: Abhijeet Kasurde --- plugins/inventory/k8s.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inventory/k8s.py b/plugins/inventory/k8s.py index d371b65c..0c663b76 100644 --- a/plugins/inventory/k8s.py +++ b/plugins/inventory/k8s.py @@ -97,7 +97,7 @@ EXAMPLES = ''' plugin: k8s connections: - host: https://192.168.64.4:8443 - token: xxxxxxxxxxxxxxxx + api_key: xxxxxxxxxxxxxxxx validate_certs: false # Use default config (~/.kube/config) file and active context, and return objects for a specific namespace From 3078131db589179011c01ce7a3f9f6080fd93b67 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Fri, 5 Jun 2020 11:32:26 +0530 Subject: [PATCH 17/88] Minor doc fixes (#114) * Spelling fixes * Documentation update * Example update to use FQCN Signed-off-by: Abhijeet Kasurde --- plugins/doc_fragments/k8s_name_options.py | 2 +- plugins/modules/helm.py | 22 +++++++++++----------- plugins/modules/helm_info.py | 12 ++++++------ plugins/modules/helm_repository.py | 10 +++++----- plugins/modules/k8s.py | 22 +++++++++++----------- plugins/modules/k8s_auth.py | 12 ++++++------ plugins/modules/k8s_exec.py | 8 ++++---- plugins/modules/k8s_info.py | 6 +++--- plugins/modules/k8s_log.py | 16 ++++++++-------- plugins/modules/k8s_scale.py | 18 +++++++++--------- plugins/modules/k8s_service.py | 10 +++++----- 11 files changed, 69 insertions(+), 69 deletions(-) diff --git a/plugins/doc_fragments/k8s_name_options.py b/plugins/doc_fragments/k8s_name_options.py index 088a5637..58840d55 100644 --- a/plugins/doc_fragments/k8s_name_options.py +++ b/plugins/doc_fragments/k8s_name_options.py @@ -42,7 +42,7 @@ options: description: - Use to specify an object namespace. Useful when creating, deleting, or discovering an object without providing a full resource definition. Use in conjunction with I(api_version), I(kind), and I(name) - to identify a specfic object. If I(resource definition) is provided, the I(metadata.namespace) value + to identify a specific object. If I(resource definition) is provided, the I(metadata.namespace) value from the I(resource_definition) will override this option. type: str ''' diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 5a5437da..e484e36d 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' --- module: helm @@ -120,9 +120,9 @@ options: type: str ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Create helm namespace as HELM 3 doesn't create it automatically - k8s: + community.kubernetes.k8s: api_version: v1 kind: Namespace name: "monitoring" @@ -130,12 +130,12 @@ EXAMPLES = ''' # From repository - name: Add stable chart repo - helm_repository: + community.kubernetes.helm_repository: name: stable repo_url: "https://kubernetes-charts.storage.googleapis.com" - name: Deploy latest version of Grafana chart inside monitoring namespace with values - helm: + community.kubernetes.helm: name: test chart_ref: stable/grafana release_namespace: monitoring @@ -143,39 +143,39 @@ EXAMPLES = ''' replicas: 2 - name: Deploy Grafana chart on 5.0.12 with values loaded from template - helm: + community.kubernetes.helm: name: test chart_ref: stable/grafana chart_version: 5.0.12 values: "{{ lookup('template', 'somefile.yaml') | from_yaml }}" - name: Remove test release and waiting suppression ending - helm: + community.kubernetes.helm: name: test state: absent wait: true # From git - name: Git clone stable repo on HEAD - git: + ansible.builtin.git: repo: "http://github.com/helm/charts.git" dest: /tmp/helm_repo - name: Deploy Grafana chart from local path - helm: + community.kubernetes.helm: name: test chart_ref: /tmp/helm_repo/stable/grafana release_namespace: monitoring # From url - name: Deploy Grafana chart on 5.0.12 from url - helm: + community.kubernetes.helm: name: test chart_ref: "https://kubernetes-charts.storage.googleapis.com/grafana-5.0.12.tgz" release_namespace: monitoring ''' -RETURN = """ +RETURN = r""" status: type: complex description: A dictionary of status output diff --git a/plugins/modules/helm_info.py b/plugins/modules/helm_info.py index cccbf250..a38271c8 100644 --- a/plugins/modules/helm_info.py +++ b/plugins/modules/helm_info.py @@ -7,11 +7,11 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' --- module: helm_info -short_description: Get informations from Helm package deployed inside the cluster +short_description: Get information from Helm package deployed inside the cluster version_added: "0.11.0" @@ -23,7 +23,7 @@ requirements: - "yaml (https://pypi.org/project/PyYAML/)" description: - - Get informations (values, states, ...) from Helm package deployed inside the cluster + - Get information (values, states, ...) from Helm package deployed inside the cluster options: binary_path: @@ -56,14 +56,14 @@ options: aliases: [ kubeconfig ] ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Deploy latest version of Grafana chart inside monitoring namespace - helm_info: + community.kubernetes.helm_info: name: test release_namespace: monitoring ''' -RETURN = """ +RETURN = r""" status: type: complex description: A dictionary of status output diff --git a/plugins/modules/helm_repository.py b/plugins/modules/helm_repository.py index e097b133..fd8a80c1 100644 --- a/plugins/modules/helm_repository.py +++ b/plugins/modules/helm_repository.py @@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' --- module: helm_repository @@ -59,21 +59,21 @@ options: repo_state: choices: ['present', 'absent'] description: - - Desirated state of repositoriy. + - Desirated state of repository. required: false default: present aliases: [ state ] type: str ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Add default repository - helm_repository: + community.kubernetes.helm_repository: name: stable repo_url: https://kubernetes-charts.storage.googleapis.com ''' -RETURN = ''' # ''' +RETURN = r''' # ''' import traceback diff --git a/plugins/modules/k8s.py b/plugins/modules/k8s.py index b7581f4d..a02d3a8f 100644 --- a/plugins/modules/k8s.py +++ b/plugins/modules/k8s.py @@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: k8s @@ -147,16 +147,16 @@ requirements: - "PyYAML >= 3.11" ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Create a k8s namespace - k8s: + community.kubernetes.k8s: name: testing api_version: v1 kind: Namespace state: present - name: Create a Service object from an inline definition - k8s: + community.kubernetes.k8s: state: present definition: apiVersion: v1 @@ -178,7 +178,7 @@ EXAMPLES = ''' port: 8000 - name: Remove an existing Service object - k8s: + community.kubernetes.k8s: state: absent api_version: v1 kind: Service @@ -188,31 +188,31 @@ EXAMPLES = ''' # Passing the object definition from a file - name: Create a Deployment by reading the definition from a local file - k8s: + community.kubernetes.k8s: state: present src: /testing/deployment.yml - name: >- Read definition file from the Ansible controller file system. If the definition file has been encrypted with Ansible Vault it will automatically be decrypted. - k8s: + community.kubernetes.k8s: state: present definition: "{{ lookup('file', '/testing/deployment.yml') | from_yaml }}" - name: Read definition file from the Ansible controller file system after Jinja templating - k8s: + community.kubernetes.k8s: state: present definition: "{{ lookup('template', '/testing/deployment.yml') | from_yaml }}" - name: fail on validation errors - k8s: + community.kubernetes.k8s: state: present definition: "{{ lookup('template', '/testing/deployment.yml') | from_yaml }}" validate: fail_on_error: yes - name: warn on validation errors, check for unexpected properties - k8s: + community.kubernetes.k8s: state: present definition: "{{ lookup('template', '/testing/deployment.yml') | from_yaml }}" validate: @@ -220,7 +220,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. diff --git a/plugins/modules/k8s_auth.py b/plugins/modules/k8s_auth.py index a02a5257..d225132c 100644 --- a/plugins/modules/k8s_auth.py +++ b/plugins/modules/k8s_auth.py @@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: k8s_auth @@ -75,7 +75,7 @@ requirements: - requests-oauthlib ''' -EXAMPLES = ''' +EXAMPLES = r''' - hosts: localhost module_defaults: group/k8s: @@ -88,7 +88,7 @@ EXAMPLES = ''' - include_vars: k8s_passwords.yml - name: Log in (obtain access token) - k8s_auth: + community.kubernetes.k8s_auth: username: admin password: "{{ k8s_admin_password }}" register: k8s_auth_results @@ -96,7 +96,7 @@ EXAMPLES = ''' # Previous task provides the token/api_key, while all other parameters # are taken from module_defaults - name: Get a list of all pods from any namespace - k8s_info: + community.kubernetes.k8s_info: api_key: "{{ k8s_auth_results.k8s_auth.api_key }}" kind: Pod register: pod_list @@ -104,7 +104,7 @@ EXAMPLES = ''' always: - name: If login succeeded, try to log out (revoke access token) when: k8s_auth_results.k8s_auth.api_key is defined - k8s_auth: + community.kubernetes.k8s_auth: state: absent api_key: "{{ k8s_auth_results.k8s_auth.api_key }}" ''' @@ -112,7 +112,7 @@ EXAMPLES = ''' # Returned value names need to match k8s modules parameter names, to make it # easy to pass returned values of k8s_auth to other k8s modules. # Discussion: https://github.com/ansible/ansible/pull/50807#discussion_r248827899 -RETURN = ''' +RETURN = r''' k8s_auth: description: Kubernetes authentication facts. returned: success diff --git a/plugins/modules/k8s_exec.py b/plugins/modules/k8s_exec.py index fe710e9c..8c7b29d6 100644 --- a/plugins/modules/k8s_exec.py +++ b/plugins/modules/k8s_exec.py @@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: k8s_exec @@ -58,15 +58,15 @@ options: required: yes ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Execute a command - k8s_exec: + community.kubernetes.k8s_exec: namespace: myproject pod: zuul-scheduler command: zuul-scheduler full-reconfigure ''' -RETURN = ''' +RETURN = r''' result: description: - The command object diff --git a/plugins/modules/k8s_info.py b/plugins/modules/k8s_info.py index af394d49..a4b2715b 100644 --- a/plugins/modules/k8s_info.py +++ b/plugins/modules/k8s_info.py @@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: k8s_info short_description: Describe Kubernetes (K8s) objects @@ -68,7 +68,7 @@ requirements: - "PyYAML >= 3.11" ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Get an existing Service object k8s_info: api_version: v1 @@ -103,7 +103,7 @@ EXAMPLES = ''' - status.phase=Running ''' -RETURN = ''' +RETURN = r''' resources: description: - The object(s) that exists diff --git a/plugins/modules/k8s_log.py b/plugins/modules/k8s_log.py index 6f8d5b46..bdf2037a 100644 --- a/plugins/modules/k8s_log.py +++ b/plugins/modules/k8s_log.py @@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: k8s_log short_description: Fetch logs from Kubernetes resources @@ -48,7 +48,7 @@ options: namespace: description: - Use to specify an object namespace. Use in conjunction with I(api_version), I(kind), and I(name) - to identify a specfic object. + to identify a specific object. type: str name: description: @@ -76,16 +76,16 @@ requirements: - "PyYAML >= 3.11" ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Get a log from a Pod - k8s_log: + community.kubernetes.k8s_log: name: example-1 namespace: testing register: log # This will get the log from the first Pod found matching the selector - name: Log a Pod matching a label selector - k8s_log: + community.kubernetes.k8s_log: namespace: testing label_selectors: - app=example @@ -93,7 +93,7 @@ EXAMPLES = ''' # This will get the log from a single Pod managed by this Deployment - name: Get a log from a Deployment - k8s_log: + community.kubernetes.k8s_log: api_version: apps/v1 kind: Deployment namespace: testing @@ -102,7 +102,7 @@ EXAMPLES = ''' # This will get the log from a single Pod managed by this DeploymentConfig - name: Get a log from a DeploymentConfig - k8s_log: + community.kubernetes.k8s_log: api_version: apps.openshift.io/v1 kind: DeploymentConfig namespace: testing @@ -110,7 +110,7 @@ EXAMPLES = ''' register: log ''' -RETURN = ''' +RETURN = r''' log: type: str description: diff --git a/plugins/modules/k8s_scale.py b/plugins/modules/k8s_scale.py index cf3a0c39..9e63366a 100644 --- a/plugins/modules/k8s_scale.py +++ b/plugins/modules/k8s_scale.py @@ -10,7 +10,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: k8s_scale @@ -36,9 +36,9 @@ requirements: - "PyYAML >= 3.11" ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Scale deployment up, and extend timeout - k8s_scale: + community.kubernetes.k8s_scale: api_version: v1 kind: Deployment name: elastic @@ -47,7 +47,7 @@ EXAMPLES = ''' wait_timeout: 60 - name: Scale deployment down when current replicas match - k8s_scale: + community.kubernetes.k8s_scale: api_version: v1 kind: Deployment name: elastic @@ -56,7 +56,7 @@ EXAMPLES = ''' replicas: 2 - name: Increase job parallelism - k8s_scale: + community.kubernetes.k8s_scale: api_version: batch/v1 kind: job name: pi-with-timeout @@ -66,25 +66,25 @@ EXAMPLES = ''' # Match object using local file or inline definition - name: Scale deployment based on a file from the local filesystem - k8s_scale: + community.kubernetes.k8s_scale: src: /myproject/elastic_deployment.yml replicas: 3 wait: no - name: Scale deployment based on a template output - k8s_scale: + community.kubernetes.k8s_scale: resource_definition: "{{ lookup('template', '/myproject/elastic_deployment.yml') | from_yaml }}" replicas: 3 wait: no - name: Scale deployment based on a file from the Ansible controller filesystem - k8s_scale: + community.kubernetes.k8s_scale: resource_definition: "{{ lookup('file', '/myproject/elastic_deployment.yml') | from_yaml }}" replicas: 3 wait: no ''' -RETURN = ''' +RETURN = r''' result: description: - If a change was made, will return the patched object, otherwise returns the existing object. diff --git a/plugins/modules/k8s_service.py b/plugins/modules/k8s_service.py index 1366caef..dcfd714b 100644 --- a/plugins/modules/k8s_service.py +++ b/plugins/modules/k8s_service.py @@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -DOCUMENTATION = ''' +DOCUMENTATION = r''' module: k8s_service @@ -121,9 +121,9 @@ requirements: - openshift >= 0.6.2 ''' -EXAMPLES = ''' +EXAMPLES = r''' - name: Expose https port with ClusterIP - k8s_service: + community.kubernetes.k8s_service: state: present name: test-https namespace: default @@ -134,7 +134,7 @@ EXAMPLES = ''' key: special - name: Expose https port with ClusterIP using spec - k8s_service: + community.kubernetes.k8s_service: state: present name: test-https namespace: default @@ -147,7 +147,7 @@ EXAMPLES = ''' key: special ''' -RETURN = ''' +RETURN = r''' result: description: - The created, patched, or otherwise present Service object. Will be empty in the case of a deletion. From c8ef0ae1ad69e7bfe5ff2c3ede984765a139c70e Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Fri, 5 Jun 2020 12:16:56 +0530 Subject: [PATCH 18/88] Minor refactor in helm_info and helm_repository (#117) Signed-off-by: Abhijeet Kasurde --- plugins/modules/helm_info.py | 12 ++++++------ plugins/modules/helm_repository.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/modules/helm_info.py b/plugins/modules/helm_info.py index a38271c8..dc02473f 100644 --- a/plugins/modules/helm_info.py +++ b/plugins/modules/helm_info.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright: Ansible Project +# Copyright: (c) 2020, Ansible Project # 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 @@ -23,7 +23,7 @@ requirements: - "yaml (https://pypi.org/project/PyYAML/)" description: - - Get information (values, states, ...) from Helm package deployed inside the cluster + - Get information (values, states, ...) from Helm package deployed inside the cluster. options: binary_path: @@ -63,7 +63,7 @@ EXAMPLES = r''' release_namespace: monitoring ''' -RETURN = r""" +RETURN = r''' status: type: complex description: A dictionary of status output @@ -101,7 +101,7 @@ status: type: str returned: always description: Dict of Values used to deploy -""" +''' import traceback @@ -211,8 +211,8 @@ def main(): if release_status is not None: module.exit_json(changed=False, status=release_status) - else: - module.exit_json(changed=False) + + module.exit_json(changed=False) if __name__ == '__main__': diff --git a/plugins/modules/helm_repository.py b/plugins/modules/helm_repository.py index fd8a80c1..cc0cadbb 100644 --- a/plugins/modules/helm_repository.py +++ b/plugins/modules/helm_repository.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright: Ansible Project +# Copyright: (c) 2020, Ansible Project # 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 @@ -23,7 +23,7 @@ requirements: - "yaml (https://pypi.org/project/PyYAML/)" description: - - Manage Helm repositories + - Manage Helm repositories. options: binary_path: From 18dfb687e6a3dbbbabec1d272f0983a8b24dfb4c Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Fri, 5 Jun 2020 12:18:57 +0530 Subject: [PATCH 19/88] Handle set object retrieved from lookup plugin (#118) api_groups is returned as "dict_keys()" which k8s lookip plugin does not handle. Typecasting with list make it available to default callback plugin. --- molecule/default/tasks/full.yml | 7 +++++++ plugins/lookup/k8s.py | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/molecule/default/tasks/full.yml b/molecule/default/tasks/full.yml index 85d5d7d4..d2666797 100644 --- a/molecule/default/tasks/full.yml +++ b/molecule/default/tasks/full.yml @@ -185,6 +185,13 @@ metadata: name: testing1 + ### https://github.com/ansible-collections/community.kubernetes/issues/111 + - set_fact: + api_groups: "{{ lookup('k8s', cluster_info='api_groups') }}" + + - debug: + var: api_groups + - name: Namespace should exist k8s_info: kind: Namespace diff --git a/plugins/lookup/k8s.py b/plugins/lookup/k8s.py index 314c52c0..bcedc976 100644 --- a/plugins/lookup/k8s.py +++ b/plugins/lookup/k8s.py @@ -194,12 +194,12 @@ RETURN = """ type: complex """ +from ansible.errors import AnsibleError +from ansible.module_utils.common._collections_compat import KeysView from ansible.plugins.lookup import LookupBase from ansible_collections.community.kubernetes.plugins.module_utils.common import K8sAnsibleMixin -from ansible.errors import AnsibleError - try: from openshift.dynamic import DynamicClient @@ -253,6 +253,8 @@ class KubernetesLookup(K8sAnsibleMixin): if cluster_info == 'version': return [self.client.version] if cluster_info == 'api_groups': + if isinstance(self.client.resources.api_groups, KeysView): + return [list(self.client.resources.api_groups)] return [self.client.resources.api_groups] self.kind = kwargs.get('kind') From 4b7db6f7f9686be4f93c77cde7d9a421c0da538d Mon Sep 17 00:00:00 2001 From: Will Thames Date: Thu, 28 May 2020 09:41:16 +1000 Subject: [PATCH 20/88] Use improved kubernetes diffs where possible Use information from strategic merges to improve the quality of diffs, particularly for list items (order no longer important, and adding/removing an item from a list just shows that item in the diff, not the whole list) --- plugins/module_utils/common.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index f9562011..6ea371bf 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -26,7 +26,6 @@ import traceback from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible.module_utils.common.dict_transformations import recursive_diff from ansible.module_utils.six import iteritems, string_types from ansible.module_utils._text import to_native @@ -57,6 +56,11 @@ try: except ImportError: pass +try: + from openshift.dynamic.apply import recursive_diff +except ImportError: + from ansible.module_utils.common.dict_transformations import recursive_diff + def list_dict_str(value): if isinstance(value, list): From 1fb38fa98295b35967ba85e7e28ca09011533a6b Mon Sep 17 00:00:00 2001 From: Will Thames Date: Tue, 9 Jun 2020 18:50:37 +1000 Subject: [PATCH 21/88] Add setup.cfg Start imposing some coding standards --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..29c924b8 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 160 +ignore = W503,E402 From 59348066a02a848b8d302906f5a9f47b2ce50877 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Tue, 9 Jun 2020 18:53:36 +1000 Subject: [PATCH 22/88] F401: Remove unused imports --- plugins/connection/kubectl.py | 1 - plugins/lookup/k8s.py | 12 ------------ plugins/module_utils/raw.py | 5 ----- plugins/modules/k8s_service.py | 2 +- 4 files changed, 1 insertion(+), 19 deletions(-) diff --git a/plugins/connection/kubectl.py b/plugins/connection/kubectl.py index b320c494..71f21e2f 100644 --- a/plugins/connection/kubectl.py +++ b/plugins/connection/kubectl.py @@ -173,7 +173,6 @@ import os import os.path import subprocess -import ansible.constants as C from ansible.parsing.yaml.loader import AnsibleLoader from ansible.errors import AnsibleError, AnsibleFileNotFound from ansible.module_utils.six.moves import shlex_quote diff --git a/plugins/lookup/k8s.py b/plugins/lookup/k8s.py index bcedc976..68fa9df5 100644 --- a/plugins/lookup/k8s.py +++ b/plugins/lookup/k8s.py @@ -202,7 +202,6 @@ from ansible_collections.community.kubernetes.plugins.module_utils.common import try: - from openshift.dynamic import DynamicClient from openshift.dynamic.exceptions import NotFoundError HAS_K8S_MODULE_HELPER = True k8s_import_exception = None @@ -210,12 +209,6 @@ except ImportError as e: HAS_K8S_MODULE_HELPER = False k8s_import_exception = e -try: - import yaml - HAS_YAML = True -except ImportError: - HAS_YAML = False - class KubernetesLookup(K8sAnsibleMixin): @@ -226,11 +219,6 @@ class KubernetesLookup(K8sAnsibleMixin): "Requires the OpenShift Python client. Try `pip install openshift`. Detail: {0}".format(k8s_import_exception) ) - if not HAS_YAML: - raise Exception( - "Requires PyYAML. Try `pip install PyYAML`" - ) - self.kind = None self.name = None self.namespace = None diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index 775deef7..59dbdf3b 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -39,11 +39,6 @@ except ImportError: # Exceptions handled in common pass -try: - import kubernetes_validate - HAS_KUBERNETES_VALIDATE = True -except ImportError: - HAS_KUBERNETES_VALIDATE = False K8S_CONFIG_HASH_IMP_ERR = None try: diff --git a/plugins/modules/k8s_service.py b/plugins/modules/k8s_service.py index dcfd714b..6df0ab5e 100644 --- a/plugins/modules/k8s_service.py +++ b/plugins/modules/k8s_service.py @@ -181,7 +181,7 @@ import traceback from collections import defaultdict -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC +from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC from ansible_collections.community.kubernetes.plugins.module_utils.raw import KubernetesRawModule From 43ae9664fc0bcdb1c147b271d9786d944bd2af55 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Tue, 9 Jun 2020 18:54:48 +1000 Subject: [PATCH 23/88] W504 Move binary operator to start of line from end of line PEP8 prefers binary operators at the start of a line https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator --- plugins/module_utils/common.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index f9562011..9120116d 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -325,21 +325,21 @@ class KubernetesAnsibleModule(AnsibleModule, K8sAnsibleMixin): # Scaling up means that we also need to check that we're not in a # situation where status.replicas == status.availableReplicas # but spec.replicas != status.replicas - return (deployment.status and - deployment.spec.replicas == (deployment.status.replicas or 0) and - deployment.status.availableReplicas == deployment.status.replicas and - deployment.status.observedGeneration == deployment.metadata.generation and - not deployment.status.unavailableReplicas) + return (deployment.status + and deployment.spec.replicas == (deployment.status.replicas or 0) + and deployment.status.availableReplicas == deployment.status.replicas + and deployment.status.observedGeneration == deployment.metadata.generation + and not deployment.status.unavailableReplicas) def _pod_ready(pod): - return (pod.status and pod.status.containerStatuses is not None and - all([container.ready for container in pod.status.containerStatuses])) + return (pod.status and pod.status.containerStatuses is not None + and all([container.ready for container in pod.status.containerStatuses])) def _daemonset_ready(daemonset): - return (daemonset.status and daemonset.status.desiredNumberScheduled is not None and - daemonset.status.numberReady == daemonset.status.desiredNumberScheduled and - daemonset.status.observedGeneration == daemonset.metadata.generation and - not daemonset.status.unavailableReplicas) + return (daemonset.status and daemonset.status.desiredNumberScheduled is not None + and daemonset.status.numberReady == daemonset.status.desiredNumberScheduled + and daemonset.status.observedGeneration == daemonset.metadata.generation + and not daemonset.status.unavailableReplicas) def _custom_condition(resource): if not resource.status or not resource.status.conditions: From 510a069de948e515e690ec866c55204ab0822e63 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Tue, 9 Jun 2020 18:59:00 +1000 Subject: [PATCH 24/88] F841 remove unused variables --- plugins/inventory/k8s.py | 2 +- plugins/modules/k8s_auth.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/inventory/k8s.py b/plugins/inventory/k8s.py index 0c663b76..9c314562 100644 --- a/plugins/inventory/k8s.py +++ b/plugins/inventory/k8s.py @@ -317,7 +317,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, K8sAnsibleM try: self.inventory.add_child(namespace_services_group, service_name) - except AnsibleError as e: + except AnsibleError: raise ports = [{'name': port.name, diff --git a/plugins/modules/k8s_auth.py b/plugins/modules/k8s_auth.py index d225132c..3af297ba 100644 --- a/plugins/modules/k8s_auth.py +++ b/plugins/modules/k8s_auth.py @@ -251,7 +251,7 @@ class KubernetesAuthModule(AnsibleModule): self.openshift_auth_endpoint = oauth_info['authorization_endpoint'] self.openshift_token_endpoint = oauth_info['token_endpoint'] - except Exception as e: + except Exception: self.fail_json(msg="Something went wrong discovering OpenShift OAuth details.", exception=traceback.format_exc()) @@ -311,7 +311,7 @@ class KubernetesAuthModule(AnsibleModule): "kind": "DeleteOptions" } - ret = requests.delete(url, headers=headers, json=json, verify=self.con_verify_ca) + requests.delete(url, headers=headers, json=json, verify=self.con_verify_ca) # Ignore errors, the token will time out eventually anyway def fail(self, msg=None): From 61c33724f335c76ec05108b81f457e58720cff34 Mon Sep 17 00:00:00 2001 From: Will Thames Date: Tue, 9 Jun 2020 19:24:37 +1000 Subject: [PATCH 25/88] Turn on flake8 checks in molecule tests --- .github/workflows/ci.yml | 2 +- molecule/default/molecule.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c47af11..acb83259 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install molecule and openshift dependencies - run: pip install molecule yamllint openshift + run: pip install molecule yamllint openshift flake8 - name: Install ansible base (devel branch) run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 37f7c3bc..37cb0028 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -9,6 +9,7 @@ driver: lint: | set -e yamllint . + flake8 platforms: - name: instance-kind provisioner: From e55053c1802f23cc5e69d3bd20998832d6c1d5c6 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 10 Jun 2020 13:57:02 -0500 Subject: [PATCH 26/88] Issue #125: Add requires_ansible version constraints to runtime.yml. --- meta/runtime.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meta/runtime.yml b/meta/runtime.yml index 3d501bae..05bb94eb 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,4 +1,6 @@ --- +requires_ansible: '>=2.9,<2.11' + action_groups: k8s: - k8s From e3f138a5305f9c18e760a7c4d13a40b722e047a6 Mon Sep 17 00:00:00 2001 From: s-hertel Date: Wed, 10 Jun 2020 15:53:30 -0400 Subject: [PATCH 27/88] Remove action_groups_redirection entry from meta/runtime.yml --- meta/runtime.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/meta/runtime.yml b/meta/runtime.yml index f36d9560..00a7eb27 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -13,7 +13,3 @@ action_groups: - k8s_log - k8s_scale - k8s_service - -action_groups_redirection: - k8s: - redirect: k8s From 3004c8d3f0ad457552dec978f5ba4719a31fac45 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Tue, 16 Jun 2020 11:03:08 +0530 Subject: [PATCH 28/88] Handle invalid kubeconfig parsing error (#119) Provide message to user about invalid or empty kubeconfig by handling exception raised by kubernetes Python API Fixes: #90 Signed-off-by: Abhijeet Kasurde --- plugins/module_utils/common.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 72046252..a94664f6 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -191,13 +191,19 @@ class K8sAnsibleMixin(object): # We have enough in the parameters to authenticate, no need to load incluster or kubeconfig pass elif auth_set('kubeconfig') or auth_set('context'): - kubernetes.config.load_kube_config(auth.get('kubeconfig'), auth.get('context'), persist_config=auth.get('persist_config')) + try: + kubernetes.config.load_kube_config(auth.get('kubeconfig'), auth.get('context'), persist_config=auth.get('persist_config')) + except Exception as err: + self.fail(msg='Failed to load kubeconfig due to %s' % to_native(err)) else: # First try to do incluster config, then kubeconfig try: kubernetes.config.load_incluster_config() except kubernetes.config.ConfigException: - kubernetes.config.load_kube_config(auth.get('kubeconfig'), auth.get('context'), persist_config=auth.get('persist_config')) + try: + kubernetes.config.load_kube_config(auth.get('kubeconfig'), auth.get('context'), persist_config=auth.get('persist_config')) + except Exception as err: + self.fail(msg='Failed to load kubeconfig due to %s' % to_native(err)) # Override any values in the default configuration with Ansible parameters configuration = kubernetes.client.Configuration() From c3796da76d465f1ebee9bdeeb2f839756da34c5e Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 16 Jun 2020 15:19:05 -0500 Subject: [PATCH 29/88] Fixes #129: Add 2.11 sanity ignore file. --- tests/sanity/ignore-2.11.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/sanity/ignore-2.11.txt diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt new file mode 100644 index 00000000..0fa8c1c3 --- /dev/null +++ b/tests/sanity/ignore-2.11.txt @@ -0,0 +1,5 @@ +plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc +plugins/modules/k8s.py validate-modules:return-syntax-error +plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc +plugins/modules/k8s_scale.py validate-modules:return-syntax-error +plugins/modules/k8s_service.py validate-modules:return-syntax-error From 5b7046470e84220b9d590ec610d57b4a8be9441f Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Thu, 18 Jun 2020 16:26:29 +0530 Subject: [PATCH 30/88] helm: Add option 'atomic' helm command provides option to remove installation on failure using 'atomic' flag. This fix adds this parameter in helm module. Fixes: #109 Signed-off-by: Abhijeet Kasurde --- meta/runtime.yml | 2 +- plugins/modules/helm.py | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/meta/runtime.yml b/meta/runtime.yml index 4f0edf6b..bcce1985 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,5 +1,5 @@ --- -requires_ansible: '>=2.9,<2.11' +requires_ansible: '>=2.9' action_groups: helm: diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index e484e36d..5b593fd9 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -118,6 +118,11 @@ options: description: - Timeout when wait option is enabled (helm2 is a number of seconds, helm3 is a duration). type: str + atomic: + description: + - If set, the installation process deletes the installation on failure. + type: bool + default: False ''' EXAMPLES = r''' @@ -230,6 +235,7 @@ command: sample: helm upgrade ... """ +import tempfile import traceback try: @@ -320,7 +326,7 @@ def fetch_chart_info(command, chart_ref): return yaml.safe_load(out) -def deploy(command, release_name, release_values, chart_name, wait, wait_timeout, disable_hook, force): +def deploy(command, release_name, release_values, chart_name, wait, wait_timeout, disable_hook, force, atomic=False): """ Install/upgrade/rollback release chart """ @@ -334,6 +340,9 @@ def deploy(command, release_name, release_values, chart_name, wait, wait_timeout if wait_timeout is not None: deploy_command += " --timeout " + wait_timeout + if atomic: + deploy_command += " --atomic" + if force: deploy_command += " --force" @@ -341,17 +350,6 @@ def deploy(command, release_name, release_values, chart_name, wait, wait_timeout deploy_command += " --no-hooks" if release_values != {}: - try: - import tempfile - except ImportError: - module.fail_json( - msg=missing_required_lib("tempfile"), - exception=traceback.format_exc(), - stdout='', - stderr='', - command='', - ) - fd, path = tempfile.mkstemp(suffix='.yml') with open(path, 'w') as yaml_file: yaml.dump(release_values, yaml_file, default_flow_style=False) @@ -402,6 +400,7 @@ def main(): purge=dict(type='bool', default=True), wait=dict(type='bool', default=False), wait_timeout=dict(type='str'), + atomic=dict(type='bool', default=False), ), required_if=[ ('release_state', 'present', ['release_name', 'chart_ref']), @@ -433,6 +432,7 @@ def main(): purge = module.params.get('purge') wait = module.params.get('wait') wait_timeout = module.params.get('wait_timeout') + atomic = module.params.get('atomic') if bin_path is not None: helm_cmd_common = bin_path @@ -471,13 +471,13 @@ def main(): if release_status is None: # Not installed helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, - disable_hook, False) + disable_hook, False, atomic=atomic) changed = True elif force or release_values != release_status['values'] \ or (chart_info['name'] + '-' + chart_info['version']) != release_status["chart"]: helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, - disable_hook, force) + disable_hook, force, atomic=atomic) changed = True if module.check_mode: From e80e3fa014d385b8be00e41a56eaafd0c3d9d098 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 16 Jun 2020 17:25:18 -0500 Subject: [PATCH 31/88] Issue #40: Add changelog and fragments and document new changelog process. --- CHANGELOG.md | 53 +----------- README.md | 5 +- changelogs/.plugin-cache.yaml | 83 ++++++++++++++++++ changelogs/CHANGELOG.rst | 86 +++++++++++++++++++ changelogs/changelog.yaml | 84 ++++++++++++++++++ changelogs/config.yaml | 29 +++++++ .../fragments/13-fix-elements-argspec.yaml | 3 + .../fragments/14-k8s_exec-new-module.yaml | 3 + .../fragments/16-k8s_log-new-module.yaml | 3 + .../fragments/33-k8s_service-fix-argspec.yaml | 3 + .../4-k8s-prepare-collection-for-release.yaml | 12 +++ .../49-k8s-add-persist_config-option.yaml | 3 + .../51-kubectl-security-disclosure.yaml | 3 + .../52-kubectl-connection-docsfix.yaml | 3 + .../54-k8s-add-exception-handling.yaml | 3 + .../56-k8s-from_yaml-docs-examples.yaml | 3 + changelogs/fragments/61-helm-new-modules.yaml | 5 ++ .../69-k8s_log-dont-parse-as-json.yaml | 3 + .../fragments/78-github-actions-workflow.yaml | 3 + .../fragments/81-rename-repository.yaml | 3 + ...clude-unnecessary-files-when-building.yaml | 3 + 21 files changed, 343 insertions(+), 53 deletions(-) create mode 100644 changelogs/.plugin-cache.yaml create mode 100644 changelogs/CHANGELOG.rst create mode 100644 changelogs/changelog.yaml create mode 100644 changelogs/config.yaml create mode 100644 changelogs/fragments/13-fix-elements-argspec.yaml create mode 100644 changelogs/fragments/14-k8s_exec-new-module.yaml create mode 100644 changelogs/fragments/16-k8s_log-new-module.yaml create mode 100644 changelogs/fragments/33-k8s_service-fix-argspec.yaml create mode 100644 changelogs/fragments/4-k8s-prepare-collection-for-release.yaml create mode 100644 changelogs/fragments/49-k8s-add-persist_config-option.yaml create mode 100644 changelogs/fragments/51-kubectl-security-disclosure.yaml create mode 100644 changelogs/fragments/52-kubectl-connection-docsfix.yaml create mode 100644 changelogs/fragments/54-k8s-add-exception-handling.yaml create mode 100644 changelogs/fragments/56-k8s-from_yaml-docs-examples.yaml create mode 100644 changelogs/fragments/61-helm-new-modules.yaml create mode 100644 changelogs/fragments/69-k8s_log-dont-parse-as-json.yaml create mode 100644 changelogs/fragments/78-github-actions-workflow.yaml create mode 100644 changelogs/fragments/81-rename-repository.yaml create mode 100644 changelogs/fragments/85-exclude-unnecessary-files-when-building.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index aeccbad0..b181d0db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,54 +1,3 @@ # Kubernetes Collection Changes -## 0.11.0 - -### New Features - - - PR #61: Add `helm`, `helm_info`, and `helm_repository` modules. - - PR #81: Rename repository to `community.kubernetes`. - -### Bug Fixes - - - PR #78: Update GitHub Actions workflow for better CI stability. - - PR #69: k8s_log no longer attempts to parse log as JSON. - - PR #85: Make sure extra files are not included in built collection. - -## 0.10.0 - -### New Features - - - PR #14: Add `k8s_exec` module for executing commands on pods via Kubernetes API. - - PR #16: Add `k8s_log` module for retrieving pod logs. - - Issue #49, PR #55: Add `persist_config` option for persisting refreshed tokens. - -### Security Fixes - - - PR #51: Warn about disclosure when using options like `kubectl_password`, `kubectl_extra_args`, and `kubectl_token` to pass data through to the command line using the `kubectl` connection plugin. - -### Bug Fixes - - - Issue #13: Fix argspec for 'elements'. - - Issue #33, PR #34: Fix argspec in `k8s_service`. - - Issue #10, PR #22: Test collection in a Kind cluster in CI using Molecule. - - PR #52: Documentation fix in `kubectl.py`. - - PR #54: Add exception handling when retrieving k8s client. - - PR #56: Use from_yaml filter with lookup examples in `k8s` module documentation examples. - -## 0.9.0 - - - Initial migration of Kubernetes content from Ansible core (2.9 / devel), including content: - - **Connection Plugins**: - - `kubectl` - - **Filter Plugins**: - - `k8s_config_resource_name` - - **Inventory Source**: - - `k8s` - - `openshift` - - **Lookup Plugins**: - - `k8s` - - **Modules**: - - `k8s` - - `k8s_auth` - - `k8s_info` - - `k8s_scale` - - `k8s_service` +The changelog has been moved to [changelogs/CHANGELOG.rst](changelogs/CHANGELOG.rst). \ No newline at end of file diff --git a/README.md b/README.md index 2f4480f1..470c28c0 100644 --- a/README.md +++ b/README.md @@ -132,8 +132,11 @@ The current process for publishing new versions of the Kubernetes Collection is 1. Ensure you're running Ansible from devel, so the [`build_ignore` key](https://github.com/ansible/ansible/issues/67130) in `galaxy.yml` is used. 1. Run `git clean -x -d -f` in this repository's directory to clean out any extra files which should not be included. - 1. Ensure `CHANGELOG.md` contains all the latest changes. 1. Update `galaxy.yml` and this README's `requirements.yml` example with the new `version` for the collection. + 1. Update the CHANGELOG: + 1. Make sure you have [`antsibull-changelog`](https://pypi.org/project/antsibull-changelog/) installed. + 1. Make sure there are fragments for all known changes in `changelogs/fragments`. + 1. Run `antsibull-changelog release` 1. Tag the version in Git and push to GitHub. 1. Run the following commands to build and release the new version on Galaxy: diff --git a/changelogs/.plugin-cache.yaml b/changelogs/.plugin-cache.yaml new file mode 100644 index 00000000..668ba958 --- /dev/null +++ b/changelogs/.plugin-cache.yaml @@ -0,0 +1,83 @@ +plugins: + become: {} + cache: {} + callback: {} + cliconf: {} + connection: + kubectl: + description: Execute tasks in pods running on Kubernetes. + name: kubectl + version_added: null + httpapi: {} + inventory: + k8s: + description: Kubernetes (K8s) inventory source + name: k8s + version_added: null + openshift: + description: OpenShift inventory source + name: openshift + version_added: null + lookup: + k8s: + description: Query the K8s API + name: k8s + version_added: null + module: + helm: + description: Manages Kubernetes packages with the Helm package manager + name: helm + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: 0.11.0 + helm_info: + description: Get information from Helm package deployed inside the cluster + name: helm_info + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: 0.11.0 + helm_repository: + description: Add and remove Helm repository + name: helm_repository + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: 0.11.0 + k8s: + description: Manage Kubernetes (K8s) objects + name: k8s + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: null + k8s_auth: + description: Authenticate to Kubernetes clusters which require an explicit login + step + name: k8s_auth + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: null + k8s_exec: + description: Execute command in Pod + name: k8s_exec + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: 0.10.0 + k8s_info: + description: Describe Kubernetes (K8s) objects + name: k8s_info + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: null + k8s_log: + description: Fetch logs from Kubernetes resources + name: k8s_log + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: 0.10.0 + k8s_scale: + description: Set a new size for a Deployment, ReplicaSet, Replication Controller, + or Job. + name: k8s_scale + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: null + k8s_service: + description: Manage Services on Kubernetes + name: k8s_service + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + version_added: null + netconf: {} + shell: {} + strategy: {} + vars: {} +version: 0.11.0 diff --git a/changelogs/CHANGELOG.rst b/changelogs/CHANGELOG.rst new file mode 100644 index 00000000..d36847b4 --- /dev/null +++ b/changelogs/CHANGELOG.rst @@ -0,0 +1,86 @@ +=================================== +Kubernetes Collection Release Notes +=================================== + +.. contents:: Topics + + +v0.11.0 +======= + +Major Changes +------------- + +- helm - New module for managing Helm charts. +- helm_info - New module for retrieving Helm chart information. +- helm_repository - New module for managing Helm repositories. + +Minor Changes +------------- + +- Rename repository to ``community.kubernetes``. + +Bugfixes +-------- + +- Make sure extra files are not included in built collection. +- Update GitHub Actions workflow for better CI stability. +- k8s_log - Module no longer attempts to parse log as JSON. + +New Modules +----------- + +- helm - Manages Kubernetes packages with the Helm package manager +- helm_info - Get information from Helm package deployed inside the cluster +- helm_repository - Add and remove Helm repository + +v0.10.0 +======= + +Major Changes +------------- + +- k8s_exec - New module for executing commands on pods via Kubernetes API. +- k8s_log - New module for retrieving pod logs. + +Minor Changes +------------- + +- k8s - Added ``persist_config`` option for persisting refreshed tokens. + +Security Fixes +-------------- + +- kubectl - Warn about information disclosure when using options like ``kubectl_password``, ``kubectl_extra_args``, and ``kubectl_token`` to pass data through to the command line using the ``kubectl`` connection plugin. + +Bugfixes +-------- + +- k8s - Add exception handling when retrieving k8s client. +- k8s - Fix argspec for 'elements'. +- k8s - Use ``from_yaml`` filter with lookup examples in ``k8s`` module documentation examples. +- k8s_service - Fix argspec. +- kubectl - Fix documentation in kubectl connection plugin. + +New Modules +----------- + +- k8s_exec - Execute command in Pod +- k8s_log - Fetch logs from Kubernetes resources + +v0.9.0 +====== + +Major Changes +------------- + +- k8s - Inventory source migrated from Ansible 2.9 to Kubernetes collection. +- k8s - Lookup plugin migrated from Ansible 2.9 to Kubernetes collection. +- k8s - Module migrated from Ansible 2.9 to Kubernetes collection. +- k8s_auth - Module migrated from Ansible 2.9 to Kubernetes collection. +- k8s_config_resource_name - Filter plugin migrated from Ansible 2.9 to Kubernetes collection. +- k8s_info - Module migrated from Ansible 2.9 to Kubernetes collection. +- k8s_scale - Module migrated from Ansible 2.9 to Kubernetes collection. +- k8s_service - Module migrated from Ansible 2.9 to Kubernetes collection. +- kubectl - Connection plugin migrated from Ansible 2.9 to Kubernetes collection. +- openshift - Inventory source migrated from Ansible 2.9 to Kubernetes collection. diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml new file mode 100644 index 00000000..765da7a7 --- /dev/null +++ b/changelogs/changelog.yaml @@ -0,0 +1,84 @@ +ancestor: null +releases: + 0.10.0: + changes: + bugfixes: + - k8s - Add exception handling when retrieving k8s client. + - k8s - Fix argspec for 'elements'. + - k8s - Use ``from_yaml`` filter with lookup examples in ``k8s`` module documentation + examples. + - k8s_service - Fix argspec. + - kubectl - Fix documentation in kubectl connection plugin. + major_changes: + - k8s_exec - New module for executing commands on pods via Kubernetes API. + - k8s_log - New module for retrieving pod logs. + minor_changes: + - k8s - Added ``persist_config`` option for persisting refreshed tokens. + security_fixes: + - kubectl - Warn about information disclosure when using options like ``kubectl_password``, + ``kubectl_extra_args``, and ``kubectl_token`` to pass data through to the + command line using the ``kubectl`` connection plugin. + fragments: + - 13-fix-elements-argspec.yaml + - 14-k8s_exec-new-module.yaml + - 16-k8s_log-new-module.yaml + - 33-k8s_service-fix-argspec.yaml + - 49-k8s-add-persist_config-option.yaml + - 51-kubectl-security-disclosure.yaml + - 52-kubectl-connection-docsfix.yaml + - 54-k8s-add-exception-handling.yaml + - 56-k8s-from_yaml-docs-examples.yaml + modules: + - description: Execute command in Pod + name: k8s_exec + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + - description: Fetch logs from Kubernetes resources + name: k8s_log + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + release_date: '2020-03-23' + 0.11.0: + changes: + bugfixes: + - Make sure extra files are not included in built collection. + - Update GitHub Actions workflow for better CI stability. + - k8s_log - Module no longer attempts to parse log as JSON. + major_changes: + - helm - New module for managing Helm charts. + - helm_info - New module for retrieving Helm chart information. + - helm_repository - New module for managing Helm repositories. + minor_changes: + - Rename repository to ``community.kubernetes``. + fragments: + - 61-helm-new-modules.yaml + - 69-k8s_log-dont-parse-as-json.yaml + - 78-github-actions-workflow.yaml + - 81-rename-repository.yaml + - 85-exclude-unnecessary-files-when-building.yaml + modules: + - description: Manages Kubernetes packages with the Helm package manager + name: helm + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + - description: Get information from Helm package deployed inside the cluster + name: helm_info + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + - description: Add and remove Helm repository + name: helm_repository + namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + release_date: '2020-05-04' + 0.9.0: + changes: + major_changes: + - k8s - Inventory source migrated from Ansible 2.9 to Kubernetes collection. + - k8s - Lookup plugin migrated from Ansible 2.9 to Kubernetes collection. + - k8s - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s_auth - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s_config_resource_name - Filter plugin migrated from Ansible 2.9 to Kubernetes + collection. + - k8s_info - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s_scale - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s_service - Module migrated from Ansible 2.9 to Kubernetes collection. + - kubectl - Connection plugin migrated from Ansible 2.9 to Kubernetes collection. + - openshift - Inventory source migrated from Ansible 2.9 to Kubernetes collection. + fragments: + - 4-k8s-prepare-collection-for-release.yaml + release_date: '2020-02-05' diff --git a/changelogs/config.yaml b/changelogs/config.yaml new file mode 100644 index 00000000..cfd96eb3 --- /dev/null +++ b/changelogs/config.yaml @@ -0,0 +1,29 @@ +changelog_filename_template: CHANGELOG.rst +changelog_filename_version_depth: 0 +changes_file: changelog.yaml +changes_format: combined +keep_fragments: true +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +prelude_section_name: release_summary +prelude_section_title: Release Summary +sections: +- - major_changes + - Major Changes +- - minor_changes + - Minor Changes +- - breaking_changes + - Breaking Changes / Porting Guide +- - deprecated_features + - Deprecated Features +- - removed_features + - Removed Features (previously deprecated) +- - security_fixes + - Security Fixes +- - bugfixes + - Bugfixes +- - known_issues + - Known Issues +title: Kubernetes Collection +trivial_section_name: trivial diff --git a/changelogs/fragments/13-fix-elements-argspec.yaml b/changelogs/fragments/13-fix-elements-argspec.yaml new file mode 100644 index 00000000..b224d921 --- /dev/null +++ b/changelogs/fragments/13-fix-elements-argspec.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - k8s - Fix argspec for 'elements'. diff --git a/changelogs/fragments/14-k8s_exec-new-module.yaml b/changelogs/fragments/14-k8s_exec-new-module.yaml new file mode 100644 index 00000000..d2aaf93a --- /dev/null +++ b/changelogs/fragments/14-k8s_exec-new-module.yaml @@ -0,0 +1,3 @@ +--- +major_changes: + - k8s_exec - New module for executing commands on pods via Kubernetes API. diff --git a/changelogs/fragments/16-k8s_log-new-module.yaml b/changelogs/fragments/16-k8s_log-new-module.yaml new file mode 100644 index 00000000..06abbf49 --- /dev/null +++ b/changelogs/fragments/16-k8s_log-new-module.yaml @@ -0,0 +1,3 @@ +--- +major_changes: + - k8s_log - New module for retrieving pod logs. diff --git a/changelogs/fragments/33-k8s_service-fix-argspec.yaml b/changelogs/fragments/33-k8s_service-fix-argspec.yaml new file mode 100644 index 00000000..bbf2af8b --- /dev/null +++ b/changelogs/fragments/33-k8s_service-fix-argspec.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - k8s_service - Fix argspec. diff --git a/changelogs/fragments/4-k8s-prepare-collection-for-release.yaml b/changelogs/fragments/4-k8s-prepare-collection-for-release.yaml new file mode 100644 index 00000000..4f9a7bcd --- /dev/null +++ b/changelogs/fragments/4-k8s-prepare-collection-for-release.yaml @@ -0,0 +1,12 @@ +--- +major_changes: + - k8s - Inventory source migrated from Ansible 2.9 to Kubernetes collection. + - k8s - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s - Lookup plugin migrated from Ansible 2.9 to Kubernetes collection. + - k8s_auth - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s_info - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s_scale - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s_service - Module migrated from Ansible 2.9 to Kubernetes collection. + - k8s_config_resource_name - Filter plugin migrated from Ansible 2.9 to Kubernetes collection. + - kubectl - Connection plugin migrated from Ansible 2.9 to Kubernetes collection. + - openshift - Inventory source migrated from Ansible 2.9 to Kubernetes collection. diff --git a/changelogs/fragments/49-k8s-add-persist_config-option.yaml b/changelogs/fragments/49-k8s-add-persist_config-option.yaml new file mode 100644 index 00000000..654cf30c --- /dev/null +++ b/changelogs/fragments/49-k8s-add-persist_config-option.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - k8s - Added ``persist_config`` option for persisting refreshed tokens. diff --git a/changelogs/fragments/51-kubectl-security-disclosure.yaml b/changelogs/fragments/51-kubectl-security-disclosure.yaml new file mode 100644 index 00000000..e0062b45 --- /dev/null +++ b/changelogs/fragments/51-kubectl-security-disclosure.yaml @@ -0,0 +1,3 @@ +--- +security_fixes: + - kubectl - Warn about information disclosure when using options like ``kubectl_password``, ``kubectl_extra_args``, and ``kubectl_token`` to pass data through to the command line using the ``kubectl`` connection plugin. diff --git a/changelogs/fragments/52-kubectl-connection-docsfix.yaml b/changelogs/fragments/52-kubectl-connection-docsfix.yaml new file mode 100644 index 00000000..44ef97a0 --- /dev/null +++ b/changelogs/fragments/52-kubectl-connection-docsfix.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - kubectl - Fix documentation in kubectl connection plugin. diff --git a/changelogs/fragments/54-k8s-add-exception-handling.yaml b/changelogs/fragments/54-k8s-add-exception-handling.yaml new file mode 100644 index 00000000..e251ed09 --- /dev/null +++ b/changelogs/fragments/54-k8s-add-exception-handling.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - k8s - Add exception handling when retrieving k8s client. diff --git a/changelogs/fragments/56-k8s-from_yaml-docs-examples.yaml b/changelogs/fragments/56-k8s-from_yaml-docs-examples.yaml new file mode 100644 index 00000000..e8fdf00c --- /dev/null +++ b/changelogs/fragments/56-k8s-from_yaml-docs-examples.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - k8s - Use ``from_yaml`` filter with lookup examples in ``k8s`` module documentation examples. diff --git a/changelogs/fragments/61-helm-new-modules.yaml b/changelogs/fragments/61-helm-new-modules.yaml new file mode 100644 index 00000000..ff10c2b4 --- /dev/null +++ b/changelogs/fragments/61-helm-new-modules.yaml @@ -0,0 +1,5 @@ +--- +major_changes: + - helm - New module for managing Helm charts. + - helm_info - New module for retrieving Helm chart information. + - helm_repository - New module for managing Helm repositories. diff --git a/changelogs/fragments/69-k8s_log-dont-parse-as-json.yaml b/changelogs/fragments/69-k8s_log-dont-parse-as-json.yaml new file mode 100644 index 00000000..a899faed --- /dev/null +++ b/changelogs/fragments/69-k8s_log-dont-parse-as-json.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - k8s_log - Module no longer attempts to parse log as JSON. diff --git a/changelogs/fragments/78-github-actions-workflow.yaml b/changelogs/fragments/78-github-actions-workflow.yaml new file mode 100644 index 00000000..aff29987 --- /dev/null +++ b/changelogs/fragments/78-github-actions-workflow.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Update GitHub Actions workflow for better CI stability. diff --git a/changelogs/fragments/81-rename-repository.yaml b/changelogs/fragments/81-rename-repository.yaml new file mode 100644 index 00000000..05ceb574 --- /dev/null +++ b/changelogs/fragments/81-rename-repository.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Rename repository to ``community.kubernetes``. diff --git a/changelogs/fragments/85-exclude-unnecessary-files-when-building.yaml b/changelogs/fragments/85-exclude-unnecessary-files-when-building.yaml new file mode 100644 index 00000000..fd7e6d68 --- /dev/null +++ b/changelogs/fragments/85-exclude-unnecessary-files-when-building.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Make sure extra files are not included in built collection. From 2dd81d6a394181878f9619444682991f79756732 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 16 Jun 2020 17:44:06 -0500 Subject: [PATCH 32/88] Issue #40: Fix YAML lint issues from changelog configs. --- .yamllint | 3 +++ changelogs/.plugin-cache.yaml | 1 + changelogs/changelog.yaml | 1 + changelogs/config.yaml | 1 + 4 files changed, 6 insertions(+) diff --git a/.yamllint b/.yamllint index c5ae64be..39cf067b 100644 --- a/.yamllint +++ b/.yamllint @@ -10,3 +10,6 @@ rules: level: error line-length: disable truthy: disable + indentation: + spaces: 2 + indent-sequences: consistent diff --git a/changelogs/.plugin-cache.yaml b/changelogs/.plugin-cache.yaml index 668ba958..d12bb24d 100644 --- a/changelogs/.plugin-cache.yaml +++ b/changelogs/.plugin-cache.yaml @@ -1,3 +1,4 @@ +--- plugins: become: {} cache: {} diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 765da7a7..a201d340 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -1,3 +1,4 @@ +--- ancestor: null releases: 0.10.0: diff --git a/changelogs/config.yaml b/changelogs/config.yaml index cfd96eb3..7500d82a 100644 --- a/changelogs/config.yaml +++ b/changelogs/config.yaml @@ -1,3 +1,4 @@ +--- changelog_filename_template: CHANGELOG.rst changelog_filename_version_depth: 0 changes_file: changelog.yaml From 49e25c8eef50b360eaa335de8ccecee955a12cdb Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 17 Jun 2020 16:58:14 -0500 Subject: [PATCH 33/88] Issue #40: gitignore the .plugin-cache.yml file. --- .gitignore | 3 ++ changelogs/.plugin-cache.yaml | 84 ----------------------------------- 2 files changed, 3 insertions(+), 84 deletions(-) delete mode 100644 changelogs/.plugin-cache.yaml diff --git a/.gitignore b/.gitignore index 0460287a..f97b7875 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ __pycache__/ # Galaxy artifacts. *.tar.gz +# Changelog cache files. +changelogs/.plugin-cache.yaml + # Temporary test files. tests/output tests/integration/cloud-config-* diff --git a/changelogs/.plugin-cache.yaml b/changelogs/.plugin-cache.yaml deleted file mode 100644 index d12bb24d..00000000 --- a/changelogs/.plugin-cache.yaml +++ /dev/null @@ -1,84 +0,0 @@ ---- -plugins: - become: {} - cache: {} - callback: {} - cliconf: {} - connection: - kubectl: - description: Execute tasks in pods running on Kubernetes. - name: kubectl - version_added: null - httpapi: {} - inventory: - k8s: - description: Kubernetes (K8s) inventory source - name: k8s - version_added: null - openshift: - description: OpenShift inventory source - name: openshift - version_added: null - lookup: - k8s: - description: Query the K8s API - name: k8s - version_added: null - module: - helm: - description: Manages Kubernetes packages with the Helm package manager - name: helm - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: 0.11.0 - helm_info: - description: Get information from Helm package deployed inside the cluster - name: helm_info - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: 0.11.0 - helm_repository: - description: Add and remove Helm repository - name: helm_repository - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: 0.11.0 - k8s: - description: Manage Kubernetes (K8s) objects - name: k8s - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: null - k8s_auth: - description: Authenticate to Kubernetes clusters which require an explicit login - step - name: k8s_auth - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: null - k8s_exec: - description: Execute command in Pod - name: k8s_exec - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: 0.10.0 - k8s_info: - description: Describe Kubernetes (K8s) objects - name: k8s_info - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: null - k8s_log: - description: Fetch logs from Kubernetes resources - name: k8s_log - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: 0.10.0 - k8s_scale: - description: Set a new size for a Deployment, ReplicaSet, Replication Controller, - or Job. - name: k8s_scale - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: null - k8s_service: - description: Manage Services on Kubernetes - name: k8s_service - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules - version_added: null - netconf: {} - shell: {} - strategy: {} - vars: {} -version: 0.11.0 From 938b01921a2e11da9683138e96c150b4820aabaa Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 17 Jun 2020 17:01:30 -0500 Subject: [PATCH 34/88] Issue #40: Generate CHANGELOG.rst in root dir. --- CHANGELOG.md | 3 --- changelogs/CHANGELOG.rst => CHANGELOG.rst | 0 changelogs/changelog.yaml | 1 - changelogs/config.yaml | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 CHANGELOG.md rename changelogs/CHANGELOG.rst => CHANGELOG.rst (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b181d0db..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# Kubernetes Collection Changes - -The changelog has been moved to [changelogs/CHANGELOG.rst](changelogs/CHANGELOG.rst). \ No newline at end of file diff --git a/changelogs/CHANGELOG.rst b/CHANGELOG.rst similarity index 100% rename from changelogs/CHANGELOG.rst rename to CHANGELOG.rst diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index a201d340..765da7a7 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -1,4 +1,3 @@ ---- ancestor: null releases: 0.10.0: diff --git a/changelogs/config.yaml b/changelogs/config.yaml index 7500d82a..519494a3 100644 --- a/changelogs/config.yaml +++ b/changelogs/config.yaml @@ -1,5 +1,5 @@ --- -changelog_filename_template: CHANGELOG.rst +changelog_filename_template: ../CHANGELOG.rst changelog_filename_version_depth: 0 changes_file: changelog.yaml changes_format: combined From d3dc3e25a497b3769361b6abac977c647482ac9c Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 17 Jun 2020 17:06:35 -0500 Subject: [PATCH 35/88] Issue #40: Manually override module namespace so extra info isn't output. --- changelogs/changelog.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 765da7a7..5bb572f6 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -31,10 +31,10 @@ releases: modules: - description: Execute command in Pod name: k8s_exec - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + namespace: '' - description: Fetch logs from Kubernetes resources name: k8s_log - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + namespace: '' release_date: '2020-03-23' 0.11.0: changes: @@ -57,13 +57,13 @@ releases: modules: - description: Manages Kubernetes packages with the Helm package manager name: helm - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + namespace: '' - description: Get information from Helm package deployed inside the cluster name: helm_info - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + namespace: '' - description: Add and remove Helm repository name: helm_repository - namespace: .ansible.collections.ansible_collections.community.kubernetes.plugins.modules + namespace: '' release_date: '2020-05-04' 0.9.0: changes: From 8674a449f742e3fc1ef739d1a5dc23dd618687fa Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Mon, 22 Jun 2020 12:33:44 -0500 Subject: [PATCH 36/88] Issue #40: Add PR and issue refs to fragments, and update CHANGELOG.rst. --- CHANGELOG.rst | 32 +++++++++---------- changelogs/changelog.yaml | 32 +++++++++---------- .../fragments/13-fix-elements-argspec.yaml | 2 +- .../fragments/14-k8s_exec-new-module.yaml | 2 +- .../fragments/16-k8s_log-new-module.yaml | 2 +- .../fragments/33-k8s_service-fix-argspec.yaml | 2 +- .../49-k8s-add-persist_config-option.yaml | 2 +- .../51-kubectl-security-disclosure.yaml | 2 +- .../52-kubectl-connection-docsfix.yaml | 2 +- .../54-k8s-add-exception-handling.yaml | 2 +- .../56-k8s-from_yaml-docs-examples.yaml | 2 +- changelogs/fragments/61-helm-new-modules.yaml | 6 ++-- .../69-k8s_log-dont-parse-as-json.yaml | 2 +- .../fragments/78-github-actions-workflow.yaml | 2 +- .../fragments/81-rename-repository.yaml | 2 +- ...clude-unnecessary-files-when-building.yaml | 2 +- 16 files changed, 48 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d36847b4..d44493ed 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,21 +11,21 @@ v0.11.0 Major Changes ------------- -- helm - New module for managing Helm charts. -- helm_info - New module for retrieving Helm chart information. -- helm_repository - New module for managing Helm repositories. +- helm - New module for managing Helm charts (https://github.com/ansible-collections/community.kubernetes/pull/61). +- helm_info - New module for retrieving Helm chart information (https://github.com/ansible-collections/community.kubernetes/pull/61). +- helm_repository - New module for managing Helm repositories (https://github.com/ansible-collections/community.kubernetes/pull/61). Minor Changes ------------- -- Rename repository to ``community.kubernetes``. +- Rename repository to ``community.kubernetes`` (https://github.com/ansible-collections/community.kubernetes/pull/81). Bugfixes -------- -- Make sure extra files are not included in built collection. -- Update GitHub Actions workflow for better CI stability. -- k8s_log - Module no longer attempts to parse log as JSON. +- Make sure extra files are not included in built collection (https://github.com/ansible-collections/community.kubernetes/pull/85). +- Update GitHub Actions workflow for better CI stability (https://github.com/ansible-collections/community.kubernetes/pull/78). +- k8s_log - Module no longer attempts to parse log as JSON (https://github.com/ansible-collections/community.kubernetes/pull/69). New Modules ----------- @@ -40,27 +40,27 @@ v0.10.0 Major Changes ------------- -- k8s_exec - New module for executing commands on pods via Kubernetes API. -- k8s_log - New module for retrieving pod logs. +- k8s_exec - New module for executing commands on pods via Kubernetes API (https://github.com/ansible-collections/community.kubernetes/pull/14). +- k8s_log - New module for retrieving pod logs (https://github.com/ansible-collections/community.kubernetes/pull/16). Minor Changes ------------- -- k8s - Added ``persist_config`` option for persisting refreshed tokens. +- k8s - Added ``persist_config`` option for persisting refreshed tokens (https://github.com/ansible-collections/community.kubernetes/issues/49). Security Fixes -------------- -- kubectl - Warn about information disclosure when using options like ``kubectl_password``, ``kubectl_extra_args``, and ``kubectl_token`` to pass data through to the command line using the ``kubectl`` connection plugin. +- kubectl - Warn about information disclosure when using options like ``kubectl_password``, ``kubectl_extra_args``, and ``kubectl_token`` to pass data through to the command line using the ``kubectl`` connection plugin (https://github.com/ansible-collections/community.kubernetes/pull/51). Bugfixes -------- -- k8s - Add exception handling when retrieving k8s client. -- k8s - Fix argspec for 'elements'. -- k8s - Use ``from_yaml`` filter with lookup examples in ``k8s`` module documentation examples. -- k8s_service - Fix argspec. -- kubectl - Fix documentation in kubectl connection plugin. +- k8s - Add exception handling when retrieving k8s client (https://github.com/ansible-collections/community.kubernetes/pull/54). +- k8s - Fix argspec for 'elements' (https://github.com/ansible-collections/community.kubernetes/issues/13). +- k8s - Use ``from_yaml`` filter with lookup examples in ``k8s`` module documentation examples (https://github.com/ansible-collections/community.kubernetes/pull/56). +- k8s_service - Fix argspec (https://github.com/ansible-collections/community.kubernetes/issues/33). +- kubectl - Fix documentation in kubectl connection plugin (https://github.com/ansible-collections/community.kubernetes/pull/52). New Modules ----------- diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 5bb572f6..1f223768 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -3,21 +3,21 @@ releases: 0.10.0: changes: bugfixes: - - k8s - Add exception handling when retrieving k8s client. - - k8s - Fix argspec for 'elements'. + - k8s - Add exception handling when retrieving k8s client (https://github.com/ansible-collections/community.kubernetes/pull/54). + - k8s - Fix argspec for 'elements' (https://github.com/ansible-collections/community.kubernetes/issues/13). - k8s - Use ``from_yaml`` filter with lookup examples in ``k8s`` module documentation - examples. - - k8s_service - Fix argspec. - - kubectl - Fix documentation in kubectl connection plugin. + examples (https://github.com/ansible-collections/community.kubernetes/pull/56). + - k8s_service - Fix argspec (https://github.com/ansible-collections/community.kubernetes/issues/33). + - kubectl - Fix documentation in kubectl connection plugin (https://github.com/ansible-collections/community.kubernetes/pull/52). major_changes: - - k8s_exec - New module for executing commands on pods via Kubernetes API. - - k8s_log - New module for retrieving pod logs. + - k8s_exec - New module for executing commands on pods via Kubernetes API (https://github.com/ansible-collections/community.kubernetes/pull/14). + - k8s_log - New module for retrieving pod logs (https://github.com/ansible-collections/community.kubernetes/pull/16). minor_changes: - - k8s - Added ``persist_config`` option for persisting refreshed tokens. + - k8s - Added ``persist_config`` option for persisting refreshed tokens (https://github.com/ansible-collections/community.kubernetes/issues/49). security_fixes: - kubectl - Warn about information disclosure when using options like ``kubectl_password``, ``kubectl_extra_args``, and ``kubectl_token`` to pass data through to the - command line using the ``kubectl`` connection plugin. + command line using the ``kubectl`` connection plugin (https://github.com/ansible-collections/community.kubernetes/pull/51). fragments: - 13-fix-elements-argspec.yaml - 14-k8s_exec-new-module.yaml @@ -39,15 +39,15 @@ releases: 0.11.0: changes: bugfixes: - - Make sure extra files are not included in built collection. - - Update GitHub Actions workflow for better CI stability. - - k8s_log - Module no longer attempts to parse log as JSON. + - Make sure extra files are not included in built collection (https://github.com/ansible-collections/community.kubernetes/pull/85). + - Update GitHub Actions workflow for better CI stability (https://github.com/ansible-collections/community.kubernetes/pull/78). + - k8s_log - Module no longer attempts to parse log as JSON (https://github.com/ansible-collections/community.kubernetes/pull/69). major_changes: - - helm - New module for managing Helm charts. - - helm_info - New module for retrieving Helm chart information. - - helm_repository - New module for managing Helm repositories. + - helm - New module for managing Helm charts (https://github.com/ansible-collections/community.kubernetes/pull/61). + - helm_info - New module for retrieving Helm chart information (https://github.com/ansible-collections/community.kubernetes/pull/61). + - helm_repository - New module for managing Helm repositories (https://github.com/ansible-collections/community.kubernetes/pull/61). minor_changes: - - Rename repository to ``community.kubernetes``. + - Rename repository to ``community.kubernetes`` (https://github.com/ansible-collections/community.kubernetes/pull/81). fragments: - 61-helm-new-modules.yaml - 69-k8s_log-dont-parse-as-json.yaml diff --git a/changelogs/fragments/13-fix-elements-argspec.yaml b/changelogs/fragments/13-fix-elements-argspec.yaml index b224d921..a9e7ef89 100644 --- a/changelogs/fragments/13-fix-elements-argspec.yaml +++ b/changelogs/fragments/13-fix-elements-argspec.yaml @@ -1,3 +1,3 @@ --- bugfixes: - - k8s - Fix argspec for 'elements'. + - k8s - Fix argspec for 'elements' (https://github.com/ansible-collections/community.kubernetes/issues/13). diff --git a/changelogs/fragments/14-k8s_exec-new-module.yaml b/changelogs/fragments/14-k8s_exec-new-module.yaml index d2aaf93a..40594b80 100644 --- a/changelogs/fragments/14-k8s_exec-new-module.yaml +++ b/changelogs/fragments/14-k8s_exec-new-module.yaml @@ -1,3 +1,3 @@ --- major_changes: - - k8s_exec - New module for executing commands on pods via Kubernetes API. + - k8s_exec - New module for executing commands on pods via Kubernetes API (https://github.com/ansible-collections/community.kubernetes/pull/14). diff --git a/changelogs/fragments/16-k8s_log-new-module.yaml b/changelogs/fragments/16-k8s_log-new-module.yaml index 06abbf49..e6ae7335 100644 --- a/changelogs/fragments/16-k8s_log-new-module.yaml +++ b/changelogs/fragments/16-k8s_log-new-module.yaml @@ -1,3 +1,3 @@ --- major_changes: - - k8s_log - New module for retrieving pod logs. + - k8s_log - New module for retrieving pod logs (https://github.com/ansible-collections/community.kubernetes/pull/16). diff --git a/changelogs/fragments/33-k8s_service-fix-argspec.yaml b/changelogs/fragments/33-k8s_service-fix-argspec.yaml index bbf2af8b..91daa0d6 100644 --- a/changelogs/fragments/33-k8s_service-fix-argspec.yaml +++ b/changelogs/fragments/33-k8s_service-fix-argspec.yaml @@ -1,3 +1,3 @@ --- bugfixes: - - k8s_service - Fix argspec. + - k8s_service - Fix argspec (https://github.com/ansible-collections/community.kubernetes/issues/33). diff --git a/changelogs/fragments/49-k8s-add-persist_config-option.yaml b/changelogs/fragments/49-k8s-add-persist_config-option.yaml index 654cf30c..ef4c3f4d 100644 --- a/changelogs/fragments/49-k8s-add-persist_config-option.yaml +++ b/changelogs/fragments/49-k8s-add-persist_config-option.yaml @@ -1,3 +1,3 @@ --- minor_changes: - - k8s - Added ``persist_config`` option for persisting refreshed tokens. + - k8s - Added ``persist_config`` option for persisting refreshed tokens (https://github.com/ansible-collections/community.kubernetes/issues/49). diff --git a/changelogs/fragments/51-kubectl-security-disclosure.yaml b/changelogs/fragments/51-kubectl-security-disclosure.yaml index e0062b45..0d2fd915 100644 --- a/changelogs/fragments/51-kubectl-security-disclosure.yaml +++ b/changelogs/fragments/51-kubectl-security-disclosure.yaml @@ -1,3 +1,3 @@ --- security_fixes: - - kubectl - Warn about information disclosure when using options like ``kubectl_password``, ``kubectl_extra_args``, and ``kubectl_token`` to pass data through to the command line using the ``kubectl`` connection plugin. + - kubectl - Warn about information disclosure when using options like ``kubectl_password``, ``kubectl_extra_args``, and ``kubectl_token`` to pass data through to the command line using the ``kubectl`` connection plugin (https://github.com/ansible-collections/community.kubernetes/pull/51). diff --git a/changelogs/fragments/52-kubectl-connection-docsfix.yaml b/changelogs/fragments/52-kubectl-connection-docsfix.yaml index 44ef97a0..ff71021c 100644 --- a/changelogs/fragments/52-kubectl-connection-docsfix.yaml +++ b/changelogs/fragments/52-kubectl-connection-docsfix.yaml @@ -1,3 +1,3 @@ --- bugfixes: - - kubectl - Fix documentation in kubectl connection plugin. + - kubectl - Fix documentation in kubectl connection plugin (https://github.com/ansible-collections/community.kubernetes/pull/52). diff --git a/changelogs/fragments/54-k8s-add-exception-handling.yaml b/changelogs/fragments/54-k8s-add-exception-handling.yaml index e251ed09..73fd6c54 100644 --- a/changelogs/fragments/54-k8s-add-exception-handling.yaml +++ b/changelogs/fragments/54-k8s-add-exception-handling.yaml @@ -1,3 +1,3 @@ --- bugfixes: - - k8s - Add exception handling when retrieving k8s client. + - k8s - Add exception handling when retrieving k8s client (https://github.com/ansible-collections/community.kubernetes/pull/54). diff --git a/changelogs/fragments/56-k8s-from_yaml-docs-examples.yaml b/changelogs/fragments/56-k8s-from_yaml-docs-examples.yaml index e8fdf00c..399b1ef8 100644 --- a/changelogs/fragments/56-k8s-from_yaml-docs-examples.yaml +++ b/changelogs/fragments/56-k8s-from_yaml-docs-examples.yaml @@ -1,3 +1,3 @@ --- bugfixes: - - k8s - Use ``from_yaml`` filter with lookup examples in ``k8s`` module documentation examples. + - k8s - Use ``from_yaml`` filter with lookup examples in ``k8s`` module documentation examples (https://github.com/ansible-collections/community.kubernetes/pull/56). diff --git a/changelogs/fragments/61-helm-new-modules.yaml b/changelogs/fragments/61-helm-new-modules.yaml index ff10c2b4..d741500d 100644 --- a/changelogs/fragments/61-helm-new-modules.yaml +++ b/changelogs/fragments/61-helm-new-modules.yaml @@ -1,5 +1,5 @@ --- major_changes: - - helm - New module for managing Helm charts. - - helm_info - New module for retrieving Helm chart information. - - helm_repository - New module for managing Helm repositories. + - helm - New module for managing Helm charts (https://github.com/ansible-collections/community.kubernetes/pull/61). + - helm_info - New module for retrieving Helm chart information (https://github.com/ansible-collections/community.kubernetes/pull/61). + - helm_repository - New module for managing Helm repositories (https://github.com/ansible-collections/community.kubernetes/pull/61). diff --git a/changelogs/fragments/69-k8s_log-dont-parse-as-json.yaml b/changelogs/fragments/69-k8s_log-dont-parse-as-json.yaml index a899faed..bf34a741 100644 --- a/changelogs/fragments/69-k8s_log-dont-parse-as-json.yaml +++ b/changelogs/fragments/69-k8s_log-dont-parse-as-json.yaml @@ -1,3 +1,3 @@ --- bugfixes: - - k8s_log - Module no longer attempts to parse log as JSON. + - k8s_log - Module no longer attempts to parse log as JSON (https://github.com/ansible-collections/community.kubernetes/pull/69). diff --git a/changelogs/fragments/78-github-actions-workflow.yaml b/changelogs/fragments/78-github-actions-workflow.yaml index aff29987..7985746e 100644 --- a/changelogs/fragments/78-github-actions-workflow.yaml +++ b/changelogs/fragments/78-github-actions-workflow.yaml @@ -1,3 +1,3 @@ --- bugfixes: - - Update GitHub Actions workflow for better CI stability. + - Update GitHub Actions workflow for better CI stability (https://github.com/ansible-collections/community.kubernetes/pull/78). diff --git a/changelogs/fragments/81-rename-repository.yaml b/changelogs/fragments/81-rename-repository.yaml index 05ceb574..dd77b24e 100644 --- a/changelogs/fragments/81-rename-repository.yaml +++ b/changelogs/fragments/81-rename-repository.yaml @@ -1,3 +1,3 @@ --- minor_changes: - - Rename repository to ``community.kubernetes``. + - Rename repository to ``community.kubernetes`` (https://github.com/ansible-collections/community.kubernetes/pull/81). diff --git a/changelogs/fragments/85-exclude-unnecessary-files-when-building.yaml b/changelogs/fragments/85-exclude-unnecessary-files-when-building.yaml index fd7e6d68..f7f4be75 100644 --- a/changelogs/fragments/85-exclude-unnecessary-files-when-building.yaml +++ b/changelogs/fragments/85-exclude-unnecessary-files-when-building.yaml @@ -1,3 +1,3 @@ --- bugfixes: - - Make sure extra files are not included in built collection. + - Make sure extra files are not included in built collection (https://github.com/ansible-collections/community.kubernetes/pull/85). From 9fb808c7f37caea0300db1b466117ad0367db492 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Thu, 25 Jun 2020 04:41:03 +0530 Subject: [PATCH 37/88] k8s: Fix a bug when manifest file ends with '---' (#139) Any kubernetes manifest file ending with '---' will generate an error when applied using 'k8s' module. Although this may not be 'legal' YAML, this is quite frequent, specially on helm's generated manifest files. migrated from https://github.com/ansible/ansible/pull/59160 Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/59160_handle_none_def.yml | 2 ++ plugins/module_utils/raw.py | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 changelogs/fragments/59160_handle_none_def.yml diff --git a/changelogs/fragments/59160_handle_none_def.yml b/changelogs/fragments/59160_handle_none_def.yml new file mode 100644 index 00000000..2c756499 --- /dev/null +++ b/changelogs/fragments/59160_handle_none_def.yml @@ -0,0 +1,2 @@ +bugfixes: +- raw - handle condition when definition is none (https://github.com/ansible/ansible/pull/59160). diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index 59dbdf3b..806d1200 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -171,6 +171,8 @@ class KubernetesRawModule(KubernetesAnsibleModule): flattened_definitions = [] for definition in self.resource_definitions: + if definition is None: + continue kind = definition.get('kind', self.kind) api_version = definition.get('apiVersion', self.api_version) if kind.endswith('List'): From 881ca3d006ae85bdd51f3890e176353de8346d48 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Mon, 29 Jun 2020 16:25:42 -0500 Subject: [PATCH 38/88] Fixes #145: Use FQCN in module docs and in plugin examples. --- README.md | 74 +++++++++++-------- plugins/inventory/k8s.py | 6 +- plugins/inventory/openshift.py | 6 +- plugins/lookup/k8s.py | 14 ++-- plugins/modules/k8s.py | 2 +- plugins/modules/k8s_info.py | 10 +-- .../kubernetes/library/test_tempfile.py | 4 +- 7 files changed, 66 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 470c28c0..04120934 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,51 @@ Content in this collection requires the [OpenShift Python client](https://pypi.o ### Using modules from the Kubernetes Collection in your playbooks -You can either call modules by their Fully Qualified Collection Namespace (FQCN), like `community.kubernetes.k8s_info`, or you can call modules by their short name if you list the `community.kubernetes` collection in the playbook's `collections`, like so: +It's preferable to use content in this collection using their Fully Qualified Collection Namespace (FQCN), for example `community.kubernetes.k8s_info`: + +```yaml +--- +- hosts: localhost + gather_facts: false + connection: local + + tasks: + - name: Ensure the myapp Namespace exists. + community.kubernetes.k8s: + api_version: v1 + kind: Namespace + name: myapp + state: present + + - name: Ensure the myapp Service exists in the myapp Namespace. + community.kubernetes.k8s: + state: present + definition: + apiVersion: v1 + kind: Service + metadata: + name: myapp + namespace: myapp + spec: + type: LoadBalancer + ports: + - port: 8080 + targetPort: 8080 + selector: + app: myapp + + - name: Get a list of all Services in the myapp namespace. + community.kubernetes.k8s_info: + kind: Service + namespace: myapp + register: myapp_services + + - name: Display number of Services in the myapp namespace. + debug: + var: myapp_services.resources | count +``` + +If upgrading older playbooks which were built prior to Ansible 2.10 and this collection's existence, you can also define `collections` in your play and refer to this collection's modules as you did in Ansible 2.9 and below, as in this example: ```yaml --- @@ -74,34 +118,6 @@ You can either call modules by their Fully Qualified Collection Namespace (FQCN) kind: Namespace name: myapp state: present - - - name: Ensure the myapp Service exists in the myapp Namespace. - k8s: - state: present - definition: - apiVersion: v1 - kind: Service - metadata: - name: myapp - namespace: myapp - spec: - type: LoadBalancer - ports: - - port: 8080 - targetPort: 8080 - selector: - app: myapp - - - name: Get a list of all Services in the myapp namespace. - k8s_info: - kind: Service - namespace: myapp - register: myapp_services - - - name: Display number of Services in the myapp namespace. - debug: - var: myapp_services.resources | count - ``` For documentation on how to use individual modules and other content included in this collection, please see the links in the 'Included content' section earlier in this README. diff --git a/plugins/inventory/k8s.py b/plugins/inventory/k8s.py index 9c314562..d2bbc3fb 100644 --- a/plugins/inventory/k8s.py +++ b/plugins/inventory/k8s.py @@ -94,20 +94,20 @@ EXAMPLES = ''' # File must be named k8s.yaml or k8s.yml # Authenticate with token, and return all pods and services for all namespaces -plugin: k8s +plugin: community.kubernetes.k8s connections: - host: https://192.168.64.4:8443 api_key: xxxxxxxxxxxxxxxx validate_certs: false # Use default config (~/.kube/config) file and active context, and return objects for a specific namespace -plugin: k8s +plugin: community.kubernetes.k8s connections: - namespaces: - testing # Use a custom config file, and a specific context. -plugin: k8s +plugin: community.kubernetes.k8s connections: - kubeconfig: /path/to/config context: 'awx/192-168-64-4:8443/developer' diff --git a/plugins/inventory/openshift.py b/plugins/inventory/openshift.py index bdd63406..f6c393bd 100644 --- a/plugins/inventory/openshift.py +++ b/plugins/inventory/openshift.py @@ -94,20 +94,20 @@ EXAMPLES = ''' # File must be named openshift.yaml or openshift.yml # Authenticate with token, and return all pods and services for all namespaces -plugin: openshift +plugin: community.kubernetes.openshift connections: - host: https://192.168.64.4:8443 api_key: xxxxxxxxxxxxxxxx verify_ssl: false # Use default config (~/.kube/config) file and active context, and return objects for a specific namespace -plugin: openshift +plugin: community.kubernetes.openshift connections: - namespaces: - testing # Use a custom config file, and a specific context. -plugin: openshift +plugin: community.kubernetes.openshift connections: - kubeconfig: /path/to/config context: 'awx/192-168-64-4:8443/developer' diff --git a/plugins/lookup/k8s.py b/plugins/lookup/k8s.py index 68fa9df5..68849053 100644 --- a/plugins/lookup/k8s.py +++ b/plugins/lookup/k8s.py @@ -133,23 +133,23 @@ DOCUMENTATION = ''' EXAMPLES = """ - name: Fetch a list of namespaces set_fact: - projects: "{{ lookup('k8s', api_version='v1', kind='Namespace') }}" + projects: "{{ lookup('community.kubernetes.k8s', api_version='v1', kind='Namespace') }}" - name: Fetch all deployments set_fact: - deployments: "{{ lookup('k8s', kind='Deployment') }}" + deployments: "{{ lookup('community.kubernetes.k8s', kind='Deployment') }}" - name: Fetch all deployments in a namespace set_fact: - deployments: "{{ lookup('k8s', kind='Deployment', namespace='testing') }}" + deployments: "{{ lookup('community.kubernetes.k8s', kind='Deployment', namespace='testing') }}" - name: Fetch a specific deployment by name set_fact: - deployments: "{{ lookup('k8s', kind='Deployment', namespace='testing', resource_name='elastic') }}" + deployments: "{{ lookup('community.kubernetes.k8s', kind='Deployment', namespace='testing', resource_name='elastic') }}" - name: Fetch with label selector set_fact: - service: "{{ lookup('k8s', kind='Service', label_selector='app=galaxy') }}" + service: "{{ lookup('community.kubernetes.k8s', kind='Service', label_selector='app=galaxy') }}" # Use parameters from a YAML config @@ -159,11 +159,11 @@ EXAMPLES = """ - name: Using the config (loaded from a file in prior task), fetch the latest version of the object set_fact: - service: "{{ lookup('k8s', resource_definition=config) }}" + service: "{{ lookup('community.kubernetes.k8s', resource_definition=config) }}" - name: Use a config from the local filesystem set_fact: - service: "{{ lookup('k8s', src='service.yml') }}" + service: "{{ lookup('community.kubernetes.k8s', src='service.yml') }}" """ RETURN = """ diff --git a/plugins/modules/k8s.py b/plugins/modules/k8s.py index a02d3a8f..54eda719 100644 --- a/plugins/modules/k8s.py +++ b/plugins/modules/k8s.py @@ -24,7 +24,7 @@ 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(community.kubernetes.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. diff --git a/plugins/modules/k8s_info.py b/plugins/modules/k8s_info.py index a4b2715b..9d598c1c 100644 --- a/plugins/modules/k8s_info.py +++ b/plugins/modules/k8s_info.py @@ -70,7 +70,7 @@ requirements: EXAMPLES = r''' - name: Get an existing Service object - k8s_info: + community.kubernetes.k8s_info: api_version: v1 kind: Service name: web @@ -78,26 +78,26 @@ EXAMPLES = r''' register: web_service - name: Get a list of all service objects - k8s_info: + community.kubernetes.k8s_info: api_version: v1 kind: Service namespace: testing register: service_list - name: Get a list of all pods from any namespace - k8s_info: + community.kubernetes.k8s_info: kind: Pod register: pod_list - name: Search for all Pods labelled app=web - k8s_info: + community.kubernetes.k8s_info: kind: Pod label_selectors: - app = web - tier in (dev, test) - name: Search for all running pods - k8s_info: + community.kubernetes.k8s_info: kind: Pod field_selectors: - status.phase=Running diff --git a/tests/integration/targets/kubernetes/library/test_tempfile.py b/tests/integration/targets/kubernetes/library/test_tempfile.py index c56377c0..c89f5a31 100644 --- a/tests/integration/targets/kubernetes/library/test_tempfile.py +++ b/tests/integration/targets/kubernetes/library/test_tempfile.py @@ -18,8 +18,8 @@ short_description: Creates temporary files and directories description: - The C(test_tempfile) module creates temporary files and directories. C(mktemp) command takes different parameters on various systems, this module helps to avoid troubles related to that. Files/directories created by module are accessible only by creator. In case you need to make them world-accessible - you need to use M(file) module. - - For Windows targets, use the M(win_tempfile) module instead. + you need to use M(ansible.builtin.file) module. + - For Windows targets, use the M(ansible.builtin.win_tempfile) module instead. options: state: From efcf870743b0cd651047bafe402b4228a9c4a577 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 1 Jul 2020 14:26:43 -0500 Subject: [PATCH 39/88] Release 0.11.1 prep - add missing changelog fragments. --- changelogs/fragments/100-k8s_scale-fix-wait.yaml | 3 +++ changelogs/fragments/102-dont-require-codecov-check-prs.yaml | 3 +++ changelogs/fragments/103-fix-inventory-docs-structure.yaml | 3 +++ changelogs/fragments/105-improved-k8s-diffs.yaml | 3 +++ changelogs/fragments/107-action-groups-module_defaults.yaml | 3 +++ changelogs/fragments/110-helm-minor-refactor.yaml | 3 +++ changelogs/fragments/114-minor-docs-fixes.yaml | 3 +++ changelogs/fragments/115-helm-add-atomic.yaml | 3 +++ changelogs/fragments/117-helm-minor-refactor.yaml | 3 +++ changelogs/fragments/118-k8s-lookup-handle-set-object.yaml | 3 +++ changelogs/fragments/119-handle-kubeconfig-error.yaml | 3 +++ changelogs/fragments/123-flake8.yaml | 3 +++ .../fragments/126-requires_ansible-version-constraints.yaml | 3 +++ changelogs/fragments/127-remove-action_groups_redirection.yaml | 3 +++ changelogs/fragments/130-add-sanity-ignore-211.yaml | 3 +++ changelogs/fragments/131-changelog-fragments.yaml | 3 +++ ...e_none_def.yml => 139-fix-manifest-ends-with-separator.yml} | 2 +- changelogs/fragments/146-fqcn-in-docs.yaml | 3 +++ changelogs/fragments/35-wait-conditions.yaml | 3 +++ changelogs/fragments/84-check_mode-service-change.yaml | 3 +++ changelogs/fragments/94-openshift-apply-test.yaml | 3 +++ changelogs/fragments/95-remove-ANSIBLE_METADATA.yaml | 3 +++ changelogs/fragments/97-remove-k8s_facts-deprecation.yaml | 3 +++ changelogs/fragments/98-add-version_added.yaml | 3 +++ 24 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/100-k8s_scale-fix-wait.yaml create mode 100644 changelogs/fragments/102-dont-require-codecov-check-prs.yaml create mode 100644 changelogs/fragments/103-fix-inventory-docs-structure.yaml create mode 100644 changelogs/fragments/105-improved-k8s-diffs.yaml create mode 100644 changelogs/fragments/107-action-groups-module_defaults.yaml create mode 100644 changelogs/fragments/110-helm-minor-refactor.yaml create mode 100644 changelogs/fragments/114-minor-docs-fixes.yaml create mode 100644 changelogs/fragments/115-helm-add-atomic.yaml create mode 100644 changelogs/fragments/117-helm-minor-refactor.yaml create mode 100644 changelogs/fragments/118-k8s-lookup-handle-set-object.yaml create mode 100644 changelogs/fragments/119-handle-kubeconfig-error.yaml create mode 100644 changelogs/fragments/123-flake8.yaml create mode 100644 changelogs/fragments/126-requires_ansible-version-constraints.yaml create mode 100644 changelogs/fragments/127-remove-action_groups_redirection.yaml create mode 100644 changelogs/fragments/130-add-sanity-ignore-211.yaml create mode 100644 changelogs/fragments/131-changelog-fragments.yaml rename changelogs/fragments/{59160_handle_none_def.yml => 139-fix-manifest-ends-with-separator.yml} (56%) create mode 100644 changelogs/fragments/146-fqcn-in-docs.yaml create mode 100644 changelogs/fragments/35-wait-conditions.yaml create mode 100644 changelogs/fragments/84-check_mode-service-change.yaml create mode 100644 changelogs/fragments/94-openshift-apply-test.yaml create mode 100644 changelogs/fragments/95-remove-ANSIBLE_METADATA.yaml create mode 100644 changelogs/fragments/97-remove-k8s_facts-deprecation.yaml create mode 100644 changelogs/fragments/98-add-version_added.yaml diff --git a/changelogs/fragments/100-k8s_scale-fix-wait.yaml b/changelogs/fragments/100-k8s_scale-fix-wait.yaml new file mode 100644 index 00000000..9dc860fa --- /dev/null +++ b/changelogs/fragments/100-k8s_scale-fix-wait.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - k8s_scale - Fix scale wait and add tests (https://github.com/ansible-collections/community.kubernetes/pull/100). diff --git a/changelogs/fragments/102-dont-require-codecov-check-prs.yaml b/changelogs/fragments/102-dont-require-codecov-check-prs.yaml new file mode 100644 index 00000000..829caf09 --- /dev/null +++ b/changelogs/fragments/102-dont-require-codecov-check-prs.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Don't require project coverage check on PRs (https://github.com/ansible-collections/community.kubernetes/pull/102). diff --git a/changelogs/fragments/103-fix-inventory-docs-structure.yaml b/changelogs/fragments/103-fix-inventory-docs-structure.yaml new file mode 100644 index 00000000..d26d99c1 --- /dev/null +++ b/changelogs/fragments/103-fix-inventory-docs-structure.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Fix suboption docs structure for inventory plugins (https://github.com/ansible-collections/community.kubernetes/pull/103). diff --git a/changelogs/fragments/105-improved-k8s-diffs.yaml b/changelogs/fragments/105-improved-k8s-diffs.yaml new file mode 100644 index 00000000..5e1f74ea --- /dev/null +++ b/changelogs/fragments/105-improved-k8s-diffs.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Use improved kubernetes diffs where possible (https://github.com/ansible-collections/community.kubernetes/pull/105). diff --git a/changelogs/fragments/107-action-groups-module_defaults.yaml b/changelogs/fragments/107-action-groups-module_defaults.yaml new file mode 100644 index 00000000..06672d98 --- /dev/null +++ b/changelogs/fragments/107-action-groups-module_defaults.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add action groups for playbooks with module_defaults (https://github.com/ansible-collections/community.kubernetes/pull/107). diff --git a/changelogs/fragments/110-helm-minor-refactor.yaml b/changelogs/fragments/110-helm-minor-refactor.yaml new file mode 100644 index 00000000..4e929176 --- /dev/null +++ b/changelogs/fragments/110-helm-minor-refactor.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - helm - minor code refactoring (https://github.com/ansible-collections/community.kubernetes/pull/110). diff --git a/changelogs/fragments/114-minor-docs-fixes.yaml b/changelogs/fragments/114-minor-docs-fixes.yaml new file mode 100644 index 00000000..106841a9 --- /dev/null +++ b/changelogs/fragments/114-minor-docs-fixes.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Minor documentation fixes and use of FQCN in some examples (https://github.com/ansible-collections/community.kubernetes/pull/114). diff --git a/changelogs/fragments/115-helm-add-atomic.yaml b/changelogs/fragments/115-helm-add-atomic.yaml new file mode 100644 index 00000000..68f5bab3 --- /dev/null +++ b/changelogs/fragments/115-helm-add-atomic.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - helm - add 'atomic' option (https://github.com/ansible-collections/community.kubernetes/pull/115). diff --git a/changelogs/fragments/117-helm-minor-refactor.yaml b/changelogs/fragments/117-helm-minor-refactor.yaml new file mode 100644 index 00000000..391932fe --- /dev/null +++ b/changelogs/fragments/117-helm-minor-refactor.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - helm_info and helm_repository - minor code refactor (https://github.com/ansible-collections/community.kubernetes/pull/117). diff --git a/changelogs/fragments/118-k8s-lookup-handle-set-object.yaml b/changelogs/fragments/118-k8s-lookup-handle-set-object.yaml new file mode 100644 index 00000000..6580f873 --- /dev/null +++ b/changelogs/fragments/118-k8s-lookup-handle-set-object.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - k8s - Handle set object retrieved from lookup plugin (https://github.com/ansible-collections/community.kubernetes/pull/118). diff --git a/changelogs/fragments/119-handle-kubeconfig-error.yaml b/changelogs/fragments/119-handle-kubeconfig-error.yaml new file mode 100644 index 00000000..97c2201f --- /dev/null +++ b/changelogs/fragments/119-handle-kubeconfig-error.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Handle invalid kubeconfig parsing error (https://github.com/ansible-collections/community.kubernetes/pull/119). diff --git a/changelogs/fragments/123-flake8.yaml b/changelogs/fragments/123-flake8.yaml new file mode 100644 index 00000000..3f9abc20 --- /dev/null +++ b/changelogs/fragments/123-flake8.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Check Python code using flake8 (https://github.com/ansible-collections/community.kubernetes/pull/123). diff --git a/changelogs/fragments/126-requires_ansible-version-constraints.yaml b/changelogs/fragments/126-requires_ansible-version-constraints.yaml new file mode 100644 index 00000000..3ff31dfa --- /dev/null +++ b/changelogs/fragments/126-requires_ansible-version-constraints.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add requires_ansible version constraints to runtime.yml (https://github.com/ansible-collections/community.kubernetes/pull/126). diff --git a/changelogs/fragments/127-remove-action_groups_redirection.yaml b/changelogs/fragments/127-remove-action_groups_redirection.yaml new file mode 100644 index 00000000..1827457c --- /dev/null +++ b/changelogs/fragments/127-remove-action_groups_redirection.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Remove action_groups_redirection entry from meta/runtime.yml (https://github.com/ansible-collections/community.kubernetes/pull/127). diff --git a/changelogs/fragments/130-add-sanity-ignore-211.yaml b/changelogs/fragments/130-add-sanity-ignore-211.yaml new file mode 100644 index 00000000..ad7af68a --- /dev/null +++ b/changelogs/fragments/130-add-sanity-ignore-211.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add sanity test ignore file for Ansible 2.11 (https://github.com/ansible-collections/community.kubernetes/pull/130). diff --git a/changelogs/fragments/131-changelog-fragments.yaml b/changelogs/fragments/131-changelog-fragments.yaml new file mode 100644 index 00000000..3b3d0397 --- /dev/null +++ b/changelogs/fragments/131-changelog-fragments.yaml @@ -0,0 +1,3 @@ +--- +major_changes: + - Add changelog and fragments and document changelog process (https://github.com/ansible-collections/community.kubernetes/pull/131). diff --git a/changelogs/fragments/59160_handle_none_def.yml b/changelogs/fragments/139-fix-manifest-ends-with-separator.yml similarity index 56% rename from changelogs/fragments/59160_handle_none_def.yml rename to changelogs/fragments/139-fix-manifest-ends-with-separator.yml index 2c756499..0b2128aa 100644 --- a/changelogs/fragments/59160_handle_none_def.yml +++ b/changelogs/fragments/139-fix-manifest-ends-with-separator.yml @@ -1,2 +1,2 @@ bugfixes: -- raw - handle condition when definition is none (https://github.com/ansible/ansible/pull/59160). +- raw - handle condition when definition is none (https://github.com/ansible-collections/community.kubernetes/pull/139). diff --git a/changelogs/fragments/146-fqcn-in-docs.yaml b/changelogs/fragments/146-fqcn-in-docs.yaml new file mode 100644 index 00000000..0ff70860 --- /dev/null +++ b/changelogs/fragments/146-fqcn-in-docs.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Use FQCN in module docs and plugin examples (https://github.com/ansible-collections/community.kubernetes/pull/146). diff --git a/changelogs/fragments/35-wait-conditions.yaml b/changelogs/fragments/35-wait-conditions.yaml new file mode 100644 index 00000000..2f6dd67c --- /dev/null +++ b/changelogs/fragments/35-wait-conditions.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Improve k8s Deployment and Daemonset wait conditions (https://github.com/ansible-collections/community.kubernetes/pull/35). diff --git a/changelogs/fragments/84-check_mode-service-change.yaml b/changelogs/fragments/84-check_mode-service-change.yaml new file mode 100644 index 00000000..974b2ace --- /dev/null +++ b/changelogs/fragments/84-check_mode-service-change.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Make sure Service changes run correctly in check_mode (https://github.com/ansible-collections/community.kubernetes/pull/84). diff --git a/changelogs/fragments/94-openshift-apply-test.yaml b/changelogs/fragments/94-openshift-apply-test.yaml new file mode 100644 index 00000000..e5a53376 --- /dev/null +++ b/changelogs/fragments/94-openshift-apply-test.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add test for openshift apply bug (https://github.com/ansible-collections/community.kubernetes/pull/94). diff --git a/changelogs/fragments/95-remove-ANSIBLE_METADATA.yaml b/changelogs/fragments/95-remove-ANSIBLE_METADATA.yaml new file mode 100644 index 00000000..e0370031 --- /dev/null +++ b/changelogs/fragments/95-remove-ANSIBLE_METADATA.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Remove deprecated ANSIBLE_METADATA field (https://github.com/ansible-collections/community.kubernetes/pull/95). diff --git a/changelogs/fragments/97-remove-k8s_facts-deprecation.yaml b/changelogs/fragments/97-remove-k8s_facts-deprecation.yaml new file mode 100644 index 00000000..5fa7abcb --- /dev/null +++ b/changelogs/fragments/97-remove-k8s_facts-deprecation.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - k8s_info - remove unneccessary k8s_facts deprecation notice (https://github.com/ansible-collections/community.kubernetes/pull/97). diff --git a/changelogs/fragments/98-add-version_added.yaml b/changelogs/fragments/98-add-version_added.yaml new file mode 100644 index 00000000..1c82b0e9 --- /dev/null +++ b/changelogs/fragments/98-add-version_added.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add version_added to each new collection module (https://github.com/ansible-collections/community.kubernetes/pull/98). From cc7d6afaf460262cd70e78c14e41f261502fbc93 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 1 Jul 2020 14:31:12 -0500 Subject: [PATCH 40/88] Prepare for release 0.11.1. --- CHANGELOG.rst | 39 +++++++++++++++++++++++++++ README.md | 5 ++-- changelogs/changelog.yaml | 55 +++++++++++++++++++++++++++++++++++++++ galaxy.yml | 2 +- 4 files changed, 98 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d44493ed..f14d8624 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,45 @@ Kubernetes Collection Release Notes .. contents:: Topics +v0.11.1 +======= + +Major Changes +------------- + +- Add changelog and fragments and document changelog process (https://github.com/ansible-collections/community.kubernetes/pull/131). + +Minor Changes +------------- + +- Add action groups for playbooks with module_defaults (https://github.com/ansible-collections/community.kubernetes/pull/107). +- Add requires_ansible version constraints to runtime.yml (https://github.com/ansible-collections/community.kubernetes/pull/126). +- Add sanity test ignore file for Ansible 2.11 (https://github.com/ansible-collections/community.kubernetes/pull/130). +- Add test for openshift apply bug (https://github.com/ansible-collections/community.kubernetes/pull/94). +- Add version_added to each new collection module (https://github.com/ansible-collections/community.kubernetes/pull/98). +- Check Python code using flake8 (https://github.com/ansible-collections/community.kubernetes/pull/123). +- Don't require project coverage check on PRs (https://github.com/ansible-collections/community.kubernetes/pull/102). +- Improve k8s Deployment and Daemonset wait conditions (https://github.com/ansible-collections/community.kubernetes/pull/35). +- Minor documentation fixes and use of FQCN in some examples (https://github.com/ansible-collections/community.kubernetes/pull/114). +- Remove action_groups_redirection entry from meta/runtime.yml (https://github.com/ansible-collections/community.kubernetes/pull/127). +- Remove deprecated ANSIBLE_METADATA field (https://github.com/ansible-collections/community.kubernetes/pull/95). +- Use FQCN in module docs and plugin examples (https://github.com/ansible-collections/community.kubernetes/pull/146). +- Use improved kubernetes diffs where possible (https://github.com/ansible-collections/community.kubernetes/pull/105). +- helm - add 'atomic' option (https://github.com/ansible-collections/community.kubernetes/pull/115). +- helm - minor code refactoring (https://github.com/ansible-collections/community.kubernetes/pull/110). +- helm_info and helm_repository - minor code refactor (https://github.com/ansible-collections/community.kubernetes/pull/117). +- k8s - Handle set object retrieved from lookup plugin (https://github.com/ansible-collections/community.kubernetes/pull/118). + +Bugfixes +-------- + +- Fix suboption docs structure for inventory plugins (https://github.com/ansible-collections/community.kubernetes/pull/103). +- Handle invalid kubeconfig parsing error (https://github.com/ansible-collections/community.kubernetes/pull/119). +- Make sure Service changes run correctly in check_mode (https://github.com/ansible-collections/community.kubernetes/pull/84). +- k8s_info - remove unneccessary k8s_facts deprecation notice (https://github.com/ansible-collections/community.kubernetes/pull/97). +- k8s_scale - Fix scale wait and add tests (https://github.com/ansible-collections/community.kubernetes/pull/100). +- raw - handle condition when definition is none (https://github.com/ansible-collections/community.kubernetes/pull/139). + v0.11.0 ======= diff --git a/README.md b/README.md index 04120934..46de5328 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ You can also include it in a `requirements.yml` file and install it via `ansible --- collections: - name: community.kubernetes - version: 0.11.0 + version: 0.11.1 ``` ### Installing the OpenShift Python Library @@ -152,7 +152,8 @@ The current process for publishing new versions of the Kubernetes Collection is 1. Update the CHANGELOG: 1. Make sure you have [`antsibull-changelog`](https://pypi.org/project/antsibull-changelog/) installed. 1. Make sure there are fragments for all known changes in `changelogs/fragments`. - 1. Run `antsibull-changelog release` + 1. Run `antsibull-changelog release`. + 1. Commit the changes and create a PR with the changes. Wait for tests to pass, then merge it once they have. 1. Tag the version in Git and push to GitHub. 1. Run the following commands to build and release the new version on Galaxy: diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 1f223768..79356fe3 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -65,6 +65,61 @@ releases: name: helm_repository namespace: '' release_date: '2020-05-04' + 0.11.1: + changes: + bugfixes: + - Fix suboption docs structure for inventory plugins (https://github.com/ansible-collections/community.kubernetes/pull/103). + - Handle invalid kubeconfig parsing error (https://github.com/ansible-collections/community.kubernetes/pull/119). + - Make sure Service changes run correctly in check_mode (https://github.com/ansible-collections/community.kubernetes/pull/84). + - k8s_info - remove unneccessary k8s_facts deprecation notice (https://github.com/ansible-collections/community.kubernetes/pull/97). + - k8s_scale - Fix scale wait and add tests (https://github.com/ansible-collections/community.kubernetes/pull/100). + - raw - handle condition when definition is none (https://github.com/ansible-collections/community.kubernetes/pull/139). + major_changes: + - Add changelog and fragments and document changelog process (https://github.com/ansible-collections/community.kubernetes/pull/131). + minor_changes: + - Add action groups for playbooks with module_defaults (https://github.com/ansible-collections/community.kubernetes/pull/107). + - Add requires_ansible version constraints to runtime.yml (https://github.com/ansible-collections/community.kubernetes/pull/126). + - Add sanity test ignore file for Ansible 2.11 (https://github.com/ansible-collections/community.kubernetes/pull/130). + - Add test for openshift apply bug (https://github.com/ansible-collections/community.kubernetes/pull/94). + - Add version_added to each new collection module (https://github.com/ansible-collections/community.kubernetes/pull/98). + - Check Python code using flake8 (https://github.com/ansible-collections/community.kubernetes/pull/123). + - Don't require project coverage check on PRs (https://github.com/ansible-collections/community.kubernetes/pull/102). + - Improve k8s Deployment and Daemonset wait conditions (https://github.com/ansible-collections/community.kubernetes/pull/35). + - Minor documentation fixes and use of FQCN in some examples (https://github.com/ansible-collections/community.kubernetes/pull/114). + - Remove action_groups_redirection entry from meta/runtime.yml (https://github.com/ansible-collections/community.kubernetes/pull/127). + - Remove deprecated ANSIBLE_METADATA field (https://github.com/ansible-collections/community.kubernetes/pull/95). + - Use FQCN in module docs and plugin examples (https://github.com/ansible-collections/community.kubernetes/pull/146). + - Use improved kubernetes diffs where possible (https://github.com/ansible-collections/community.kubernetes/pull/105). + - helm - add 'atomic' option (https://github.com/ansible-collections/community.kubernetes/pull/115). + - helm - minor code refactoring (https://github.com/ansible-collections/community.kubernetes/pull/110). + - helm_info and helm_repository - minor code refactor (https://github.com/ansible-collections/community.kubernetes/pull/117). + - k8s - Handle set object retrieved from lookup plugin (https://github.com/ansible-collections/community.kubernetes/pull/118). + fragments: + - 100-k8s_scale-fix-wait.yaml + - 102-dont-require-codecov-check-prs.yaml + - 103-fix-inventory-docs-structure.yaml + - 105-improved-k8s-diffs.yaml + - 107-action-groups-module_defaults.yaml + - 110-helm-minor-refactor.yaml + - 114-minor-docs-fixes.yaml + - 115-helm-add-atomic.yaml + - 117-helm-minor-refactor.yaml + - 118-k8s-lookup-handle-set-object.yaml + - 119-handle-kubeconfig-error.yaml + - 123-flake8.yaml + - 126-requires_ansible-version-constraints.yaml + - 127-remove-action_groups_redirection.yaml + - 130-add-sanity-ignore-211.yaml + - 131-changelog-fragments.yaml + - 139-fix-manifest-ends-with-separator.yml + - 146-fqcn-in-docs.yaml + - 35-wait-conditions.yaml + - 84-check_mode-service-change.yaml + - 94-openshift-apply-test.yaml + - 95-remove-ANSIBLE_METADATA.yaml + - 97-remove-k8s_facts-deprecation.yaml + - 98-add-version_added.yaml + release_date: '2020-07-01' 0.9.0: changes: major_changes: diff --git a/galaxy.yml b/galaxy.yml index c17e1d06..f3e4dfd9 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -26,7 +26,7 @@ tags: - openshift - okd - cluster -version: 0.11.0 +version: 0.11.1 build_ignore: - .DS_Store - '*.tar.gz' From ef6722d29049ea05b7675cce4a9bf81f771452b9 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Thu, 2 Jul 2020 18:48:41 +0530 Subject: [PATCH 41/88] helm: Add support for K8S_AUTH_CONTEXT, K8S_AUTH_KUBECONFIG env (#141) Added support for K8S_AUTH_CONTEXT, K8S_AUTH_KUBECONFIG env --- changelogs/fragments/140_kubeconfig_env.yaml | 3 +++ plugins/modules/helm.py | 8 +++++--- plugins/modules/helm_info.py | 8 +++++--- 3 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/140_kubeconfig_env.yaml diff --git a/changelogs/fragments/140_kubeconfig_env.yaml b/changelogs/fragments/140_kubeconfig_env.yaml new file mode 100644 index 00000000..48a3e99a --- /dev/null +++ b/changelogs/fragments/140_kubeconfig_env.yaml @@ -0,0 +1,3 @@ +minor_changes: +- helm - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). +- helm_info - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 5b593fd9..9ca1beed 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -98,10 +98,12 @@ options: kube_context: description: - Helm option to specify which kubeconfig context to use. + - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_CONTEXT) will be used instead. type: str kubeconfig_path: description: - Helm option to specify kubeconfig path to use. + - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_KUBECONFIG) will be used instead. type: path aliases: [ kubeconfig ] purge: @@ -245,7 +247,7 @@ except ImportError: IMP_YAML_ERR = traceback.format_exc() IMP_YAML = False -from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible.module_utils.basic import AnsibleModule, missing_required_lib, env_fallback module = None @@ -395,8 +397,8 @@ def main(): # Helm options disable_hook=dict(type='bool', default=False), force=dict(type='bool', default=False), - kube_context=dict(type='str'), - kubeconfig_path=dict(type='path', aliases=['kubeconfig']), + kube_context=dict(type='str', fallback=(env_fallback, ['K8S_AUTH_CONTEXT'])), + kubeconfig_path=dict(type='path', aliases=['kubeconfig'], fallback=(env_fallback, ['K8S_AUTH_KUBECONFIG'])), purge=dict(type='bool', default=True), wait=dict(type='bool', default=False), wait_timeout=dict(type='str'), diff --git a/plugins/modules/helm_info.py b/plugins/modules/helm_info.py index dc02473f..1e514138 100644 --- a/plugins/modules/helm_info.py +++ b/plugins/modules/helm_info.py @@ -48,10 +48,12 @@ options: kube_context: description: - Helm option to specify which kubeconfig context to use. + - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_CONTEXT) will be used instead. type: str kubeconfig_path: description: - Helm option to specify kubeconfig path to use. + - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_KUBECONFIG) will be used instead. type: path aliases: [ kubeconfig ] ''' @@ -112,7 +114,7 @@ except ImportError: IMP_YAML_ERR = traceback.format_exc() IMP_YAML = False -from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible.module_utils.basic import AnsibleModule, missing_required_lib, env_fallback module = None @@ -177,8 +179,8 @@ def main(): release_namespace=dict(type='str', required=True, aliases=['namespace']), # Helm options - kube_context=dict(type='str'), - kubeconfig_path=dict(type='path', aliases=['kubeconfig']), + kube_context=dict(type='str', fallback=(env_fallback, ['K8S_AUTH_CONTEXT'])), + kubeconfig_path=dict(type='path', aliases=['kubeconfig'], fallback=(env_fallback, ['K8S_AUTH_KUBECONFIG'])), ), supports_check_mode=True, ) From 48a45de8b091de1e8d902024841a5873ff16123e Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 6 Jul 2020 11:18:23 +0530 Subject: [PATCH 42/88] helm_: Add context aliases for kube_context Added 'context' aliases for 'kube_context' in helm and helm_info module. Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/helm_context_aliases.yml | 3 +++ plugins/modules/helm.py | 3 ++- plugins/modules/helm_info.py | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/helm_context_aliases.yml diff --git a/changelogs/fragments/helm_context_aliases.yml b/changelogs/fragments/helm_context_aliases.yml new file mode 100644 index 00000000..02a0e909 --- /dev/null +++ b/changelogs/fragments/helm_context_aliases.yml @@ -0,0 +1,3 @@ +minor_changes: +- helm - add aliases context for kube_context. +- helm_info - add aliases context for kube_context. diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 9ca1beed..edd87c82 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -100,6 +100,7 @@ options: - Helm option to specify which kubeconfig context to use. - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_CONTEXT) will be used instead. type: str + aliases: [ context ] kubeconfig_path: description: - Helm option to specify kubeconfig path to use. @@ -397,7 +398,7 @@ def main(): # Helm options disable_hook=dict(type='bool', default=False), force=dict(type='bool', default=False), - kube_context=dict(type='str', fallback=(env_fallback, ['K8S_AUTH_CONTEXT'])), + kube_context=dict(type='str', aliases=['context'], fallback=(env_fallback, ['K8S_AUTH_CONTEXT'])), kubeconfig_path=dict(type='path', aliases=['kubeconfig'], fallback=(env_fallback, ['K8S_AUTH_KUBECONFIG'])), purge=dict(type='bool', default=True), wait=dict(type='bool', default=False), diff --git a/plugins/modules/helm_info.py b/plugins/modules/helm_info.py index 1e514138..31c6fab9 100644 --- a/plugins/modules/helm_info.py +++ b/plugins/modules/helm_info.py @@ -50,6 +50,7 @@ options: - Helm option to specify which kubeconfig context to use. - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_CONTEXT) will be used instead. type: str + aliases: [ context ] kubeconfig_path: description: - Helm option to specify kubeconfig path to use. @@ -179,7 +180,7 @@ def main(): release_namespace=dict(type='str', required=True, aliases=['namespace']), # Helm options - kube_context=dict(type='str', fallback=(env_fallback, ['K8S_AUTH_CONTEXT'])), + kube_context=dict(type='str', aliases=['context'], fallback=(env_fallback, ['K8S_AUTH_CONTEXT'])), kubeconfig_path=dict(type='path', aliases=['kubeconfig'], fallback=(env_fallback, ['K8S_AUTH_KUBECONFIG'])), ), supports_check_mode=True, From 9aa85e8eb5dca762e1032502b2d869091165ba82 Mon Sep 17 00:00:00 2001 From: Yaakov Selkowitz Date: Mon, 6 Jul 2020 11:10:59 -0400 Subject: [PATCH 43/88] Update openshift requirements in k8s module doc --- plugins/modules/k8s.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/modules/k8s.py b/plugins/modules/k8s.py index 54eda719..23cf2f45 100644 --- a/plugins/modules/k8s.py +++ b/plugins/modules/k8s.py @@ -111,7 +111,7 @@ options: validate: description: - how (if at all) to validate the resource definition against the kubernetes schema. - Requires the kubernetes-validate python module + Requires the kubernetes-validate python module and openshift >= 0.8.0 suboptions: fail_on_error: description: whether to fail on validation errors. @@ -132,12 +132,14 @@ 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 type: bool apply: description: - 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) type: bool From e3223a8f603916e2ff3c91435556d66d676d84ed Mon Sep 17 00:00:00 2001 From: Will Thames Date: Wed, 8 Jul 2020 21:47:23 +1000 Subject: [PATCH 44/88] Ensure check mode results are as expected check_mode with wait updates the result based on the existing resource which won't change with check_mode, so returns incorrect results. Only run the wait checks in non check_mode (this also avoids the issue of waiting for resource creation that will never happen in check mode) --- molecule/default/tasks/apply.yml | 46 +++++++++++++++++++++++++++++++ molecule/default/tasks/waiter.yml | 4 ++- plugins/module_utils/raw.py | 6 ++-- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/molecule/default/tasks/apply.yml b/molecule/default/tasks/apply.yml index ca4fa284..2f579755 100644 --- a/molecule/default/tasks/apply.yml +++ b/molecule/default/tasks/apply.yml @@ -324,6 +324,45 @@ cpu: 100m memory: 100Mi + - name: Update the earlier deployment in check mode + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: apply-deploy + namespace: "{{ apply_namespace }}" + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + apply: yes + check_mode: yes + vars: + k8s_pod_name: apply-deploy + k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple + k8s_pod_service_account: apply-deploy + k8s_pod_ports: + - containerPort: 8080 + name: http + protocol: TCP + k8s_pod_resources: + requests: + cpu: 50m + limits: + cpu: 50m + memory: 50Mi + register: update_deploy_check_mode + + - name: Ensure check mode change took + assert: + that: + - update_deploy_check_mode is changed + - "update_deploy_check_mode.result.spec.template.spec.containers[0].image == 'gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple'" + - name: Update the earlier deployment k8s: definition: @@ -354,6 +393,13 @@ limits: cpu: 50m memory: 50Mi + register: update_deploy_for_real + + - name: Ensure change took + assert: + that: + - update_deploy_for_real is changed + - "update_deploy_for_real.result.spec.template.spec.containers[0].image == 'gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple'" - name: Remove the serviceaccount k8s: diff --git a/molecule/default/tasks/waiter.yml b/molecule/default/tasks/waiter.yml index 5434e967..4049f6ef 100644 --- a/molecule/default/tasks/waiter.yml +++ b/molecule/default/tasks/waiter.yml @@ -83,11 +83,13 @@ k8s_pod_name: wait-ds k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:2 register: update_ds_check_mode + check_mode: yes - - name: Check that check_mode returned changed + - name: Check that check_mode result contains the changes assert: that: - update_ds_check_mode is changed + - "update_ds_check_mode.result.spec.template.spec.containers[0].image == 'gcr.io/kuar-demo/kuard-amd64:2'" - name: Update a daemonset k8s: diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index 806d1200..47c7443c 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -309,7 +309,7 @@ class KubernetesRawModule(KubernetesAnsibleModule): self.fail_json(msg=msg, error=exc.status, status=exc.status, reason=exc.reason) success = True result['result'] = k8s_obj - if wait: + if wait and not self.check_mode: success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout, condition=wait_condition) if existing: existing = existing.to_dict() @@ -368,7 +368,7 @@ class KubernetesRawModule(KubernetesAnsibleModule): match, diffs = self.diff_objects(existing.to_dict(), k8s_obj) success = True result['result'] = k8s_obj - if wait: + if wait and not self.check_mode: success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout, condition=wait_condition) match, diffs = self.diff_objects(existing.to_dict(), result['result']) result['changed'] = not match @@ -396,7 +396,7 @@ class KubernetesRawModule(KubernetesAnsibleModule): success = True result['result'] = k8s_obj - if wait: + if wait and not self.check_mode: success, result['result'], result['duration'] = self.wait(resource, definition, wait_sleep, wait_timeout, condition=wait_condition) match, diffs = self.diff_objects(existing.to_dict(), result['result']) result['changed'] = not match From 3e971e0ad36a05a9ad63f442204c2dd59bbf558e Mon Sep 17 00:00:00 2001 From: LucasBoisserie Date: Sat, 11 Jul 2020 05:15:22 +0200 Subject: [PATCH 45/88] Create ns with helm (#157) Added support `--create-namespace` in helm module. --- molecule/default/roles/helm/tasks/main.yml | 2 +- .../default/roles/helm/tasks/tests_chart.yml | 24 ++++++++++----- plugins/modules/helm.py | 29 +++++++++++++------ 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/molecule/default/roles/helm/tasks/main.yml b/molecule/default/roles/helm/tasks/main.yml index 458775de..e86d33df 100644 --- a/molecule/default/roles/helm/tasks/main.yml +++ b/molecule/default/roles/helm/tasks/main.yml @@ -4,4 +4,4 @@ loop_control: loop_var: helm_version with_items: - - "v3.1.2" + - "v3.2.4" diff --git a/molecule/default/roles/helm/tasks/tests_chart.yml b/molecule/default/roles/helm/tasks/tests_chart.yml index eb6d518f..b0341330 100644 --- a/molecule/default/roles/helm/tasks/tests_chart.yml +++ b/molecule/default/roles/helm/tasks/tests_chart.yml @@ -1,11 +1,4 @@ --- -- name: Create helm namespace - k8s: - api_version: v1 - kind: Namespace - name: "{{ helm_namespace }}" - wait: true - - name: Check helm_info empty helm_info: binary_path: "{{ helm_binary }}" @@ -18,6 +11,22 @@ that: - empty_info.status is undefined +- name: "Install fail {{ chart_test }} from {{ source }}" + helm: + binary_path: "{{ helm_binary }}" + name: test + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + ignore_errors: yes + register: install_fail + +- name: "Assert that Install fail {{ chart_test }} from {{ source }}" + assert: + that: + - install_fail is failed + - "'Error: create: failed to create: namespaces \"' + helm_namespace + '\" not found' in install_fail.stderr" + - name: "Install {{ chart_test }} from {{ source }}" helm: binary_path: "{{ helm_binary }}" @@ -25,6 +34,7 @@ chart_ref: "{{ chart_source }}" chart_version: "{{ chart_source_version | default(omit) }}" namespace: "{{ helm_namespace }}" + create_namespace: true register: install - name: "Assert that {{ chart_test }} chart is installed from {{ source }}" diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index edd87c82..a0972341 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -126,15 +126,21 @@ options: - If set, the installation process deletes the installation on failure. type: bool default: False + create_namespace: + description: + - Create the release namespace if not present. + type: bool + default: False + version_added: "0.11.1" ''' EXAMPLES = r''' -- name: Create helm namespace as HELM 3 doesn't create it automatically - community.kubernetes.k8s: - api_version: v1 - kind: Namespace - name: "monitoring" - wait: true +- name: Deploy latest version of Prometheus chart inside monitoring namespace (and create it) + community.kubernetes.helm: + name: test + chart_ref: stable/prometheus + release_namespace: monitoring + create_namespace: true # From repository - name: Add stable chart repo @@ -329,7 +335,7 @@ def fetch_chart_info(command, chart_ref): return yaml.safe_load(out) -def deploy(command, release_name, release_values, chart_name, wait, wait_timeout, disable_hook, force, atomic=False): +def deploy(command, release_name, release_values, chart_name, wait, wait_timeout, disable_hook, force, atomic=False, create_namespace=False): """ Install/upgrade/rollback release chart """ @@ -352,6 +358,9 @@ def deploy(command, release_name, release_values, chart_name, wait, wait_timeout if disable_hook: deploy_command += " --no-hooks" + if create_namespace: + deploy_command += " --create-namespace" + if release_values != {}: fd, path = tempfile.mkstemp(suffix='.yml') with open(path, 'w') as yaml_file: @@ -404,6 +413,7 @@ def main(): wait=dict(type='bool', default=False), wait_timeout=dict(type='str'), atomic=dict(type='bool', default=False), + create_namespace=dict(type='bool', default=False), ), required_if=[ ('release_state', 'present', ['release_name', 'chart_ref']), @@ -436,6 +446,7 @@ def main(): wait = module.params.get('wait') wait_timeout = module.params.get('wait_timeout') atomic = module.params.get('atomic') + create_namespace = module.params.get('create_namespace') if bin_path is not None: helm_cmd_common = bin_path @@ -474,13 +485,13 @@ def main(): if release_status is None: # Not installed helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, - disable_hook, False, atomic=atomic) + disable_hook, False, atomic=atomic, create_namespace=create_namespace) changed = True elif force or release_values != release_status['values'] \ or (chart_info['name'] + '-' + chart_info['version']) != release_status["chart"]: helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, - disable_hook, force, atomic=atomic) + disable_hook, force, atomic=atomic, create_namespace=create_namespace) changed = True if module.check_mode: From 6b28ef3c17449fdd34d0b51c3846278db80239c7 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Sat, 11 Jul 2020 08:50:15 +0530 Subject: [PATCH 46/88] kubectl: redacted token and password from console log (#159) ** SECURITY_FIX ** for CVE-2020-1753 kubectl connection plugin now redact kubectl_token and kubectl_password from console log. Fixes: #65 Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/65_kubectl.yml | 2 ++ plugins/connection/kubectl.py | 28 +++++++++++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 changelogs/fragments/65_kubectl.yml diff --git a/changelogs/fragments/65_kubectl.yml b/changelogs/fragments/65_kubectl.yml new file mode 100644 index 00000000..0c30a61b --- /dev/null +++ b/changelogs/fragments/65_kubectl.yml @@ -0,0 +1,2 @@ +security_fixes: +- kubectl - connection plugin now redact kubectl_token and kubectl_password in console log (https://github.com/ansible-collections/community.kubernetes/issues/65). diff --git a/plugins/connection/kubectl.py b/plugins/connection/kubectl.py index 71f21e2f..f3015e2e 100644 --- a/plugins/connection/kubectl.py +++ b/plugins/connection/kubectl.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -DOCUMENTATION = """ +DOCUMENTATION = r""" author: - xuxinkun @@ -38,7 +38,8 @@ DOCUMENTATION = """ options: kubectl_pod: description: - - Pod name. Required when the host name does not match pod name. + - Pod name. + - Required when the host name does not match pod name. default: '' vars: - name: ansible_kubectl_pod @@ -46,7 +47,8 @@ DOCUMENTATION = """ - name: K8S_AUTH_POD kubectl_container: description: - - Container name. Required when a pod contains more than one container. + - Container name. + - Required when a pod contains more than one container. default: '' vars: - name: ansible_kubectl_container @@ -226,7 +228,7 @@ class Connection(ConnectionBase): def _build_exec_cmd(self, cmd): """ Build the local kubectl exec command to run cmd on remote_host """ - local_cmd = [self.transport_cmd] + local_cmd = censored_local_cmd = [self.transport_cmd] # Build command options based on doc string doc_yaml = AnsibleLoader(self.documentation).get_single_data() @@ -235,28 +237,36 @@ class Connection(ConnectionBase): # Translate verify_ssl to skip_verify_ssl, and output as string skip_verify_ssl = not self.get_option(key) local_cmd.append(u'{0}={1}'.format(self.connection_options[key], str(skip_verify_ssl).lower())) + censored_local_cmd.append(u'{0}={1}'.format(self.connection_options[key], str(skip_verify_ssl).lower())) elif not key.endswith('container') and self.get_option(key) and self.connection_options.get(key): cmd_arg = self.connection_options[key] local_cmd += [cmd_arg, self.get_option(key)] + # Redact password and token from console log + if key.endswith(('_token', '_password')): + censored_local_cmd += [cmd_arg, '********'] extra_args_name = u'{0}_extra_args'.format(self.transport) if self.get_option(extra_args_name): local_cmd += self.get_option(extra_args_name).split(' ') + censored_local_cmd += self.get_option(extra_args_name).split(' ') pod = self.get_option(u'{0}_pod'.format(self.transport)) if not pod: pod = self._play_context.remote_addr # -i is needed to keep stdin open which allows pipelining to work local_cmd += ['exec', '-i', pod] + censored_local_cmd += ['exec', '-i', pod] # if the pod has more than one container, then container is required container_arg_name = u'{0}_container'.format(self.transport) if self.get_option(container_arg_name): local_cmd += ['-c', self.get_option(container_arg_name)] + censored_local_cmd += ['-c', self.get_option(container_arg_name)] local_cmd += ['--'] + cmd + censored_local_cmd += ['--'] + cmd - return local_cmd + return local_cmd, censored_local_cmd def _connect(self, port=None): """ Connect to the container. Nothing to do """ @@ -269,9 +279,9 @@ class Connection(ConnectionBase): """ Run a command in the container """ super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) - local_cmd = self._build_exec_cmd([self._play_context.executable, '-c', cmd]) + local_cmd, censored_local_cmd = self._build_exec_cmd([self._play_context.executable, '-c', cmd]) - display.vvv("EXEC %s" % (local_cmd,), host=self._play_context.remote_addr) + display.vvv("EXEC %s" % (censored_local_cmd,), host=self._play_context.remote_addr) local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd] p = subprocess.Popen(local_cmd, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -311,7 +321,7 @@ class Connection(ConnectionBase): count = ' count=0' else: count = '' - args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s%s" % (out_path, BUFSIZE, count)]) + args, dummy = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s%s" % (out_path, BUFSIZE, count)]) args = [to_bytes(i, errors='surrogate_or_strict') for i in args] try: p = subprocess.Popen(args, stdin=in_file, @@ -333,7 +343,7 @@ class Connection(ConnectionBase): # kubectl doesn't have native support for fetching files from # running containers, so we use kubectl exec to implement this - args = self._build_exec_cmd([self._play_context.executable, "-c", "dd if=%s bs=%s" % (in_path, BUFSIZE)]) + args, dummy = self._build_exec_cmd([self._play_context.executable, "-c", "dd if=%s bs=%s" % (in_path, BUFSIZE)]) args = [to_bytes(i, errors='surrogate_or_strict') for i in args] actual_out_path = os.path.join(out_dir, os.path.basename(in_path)) with open(to_bytes(actual_out_path, errors='surrogate_or_strict'), 'wb') as out_file: From c4f3e5a03464f75d13b33b8d831a203e3856e058 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 13 Jul 2020 16:35:33 +0530 Subject: [PATCH 47/88] k8s_info: Update example using vars (#156) Fixes: #151 Signed-off-by: Abhijeet Kasurde --- plugins/modules/k8s_info.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/modules/k8s_info.py b/plugins/modules/k8s_info.py index 9d598c1c..0fc6ab94 100644 --- a/plugins/modules/k8s_info.py +++ b/plugins/modules/k8s_info.py @@ -96,6 +96,14 @@ EXAMPLES = r''' - app = web - tier in (dev, test) +- name: Using vars while using label_selectors + community.kubernetes.k8s_info: + kind: Pod + label_selectors: + - "app = {{ app_label_web }}" + vars: + app_label_web: web + - name: Search for all running pods community.kubernetes.k8s_info: kind: Pod From a16ac42f3edaa4419dffa5c04be85b8b4aa98611 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Fri, 17 Jul 2020 08:55:11 -0500 Subject: [PATCH 48/88] Issue #148: Switch links and CI process to main from master branch. --- .github/workflows/ci.yml | 2 +- README.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index acb83259..63e458be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ name: CI 'on': push: branches: - - master + - main pull_request: schedule: - cron: '0 6 * * *' diff --git a/README.md b/README.md index 46de5328..2cd04be0 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,14 @@ Click on the name of a plugin or module to view that content's documentation: - **Modules**: - [k8s](https://docs.ansible.com/ansible/latest/modules/k8s_module.html) - [k8s_auth](https://docs.ansible.com/ansible/latest/modules/k8s_auth_module.html) - - [k8s_exec](https://github.com/ansible-collections/community.kubernetes/blob/master/plugins/modules/k8s_exec.py) - - [k8s_log](https://github.com/ansible-collections/community.kubernetes/blob/master/plugins/modules/k8s_log.py) + - [k8s_exec](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/k8s_exec.py) + - [k8s_log](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/k8s_log.py) - [k8s_info](https://docs.ansible.com/ansible/latest/modules/k8s_info_module.html) - [k8s_scale](https://docs.ansible.com/ansible/latest/modules/k8s_scale_module.html) - [k8s_service](https://docs.ansible.com/ansible/latest/modules/k8s_service_module.html) - - [helm](https://github.com/ansible-collections/community.kubernetes/blob/master/plugins/modules/helm.py) - - [helm_info](https://github.com/ansible-collections/community.kubernetes/blob/master/plugins/modules/helm_info.py) - - [helm_repository](https://github.com/ansible-collections/community.kubernetes/blob/master/plugins/modules/helm_repository.py) + - [helm](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/helm.py) + - [helm_info](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/helm_info.py) + - [helm_repository](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/helm_repository.py) ## Installation and Usage From 6d2567b6c05e9357cb2ed48d1bc6c6cbeb3747d6 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Mon, 20 Jul 2020 16:06:40 -0500 Subject: [PATCH 49/88] Fixes #167: Re-order ansible installation so it doesn't break on molecule test. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63e458be..c5ebde97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,12 +83,12 @@ jobs: with: python-version: ${{ matrix.python_version }} - - name: Install molecule and openshift dependencies - run: pip install molecule yamllint openshift flake8 - - name: Install ansible base (devel branch) run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + - name: Install molecule and openshift dependencies + run: pip install molecule yamllint openshift flake8 + - name: Create default collection path symlink run: | mkdir -p /home/runner/.ansible From 4a2b1b918b2a0cb2a2ddb4af0ccfcd24eed4052f Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Mon, 20 Jul 2020 16:25:35 -0500 Subject: [PATCH 50/88] Issue #167: Make yamllint less bothersome and install ansible-base in different order. --- .github/workflows/ci.yml | 8 +++++--- .yamllint | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5ebde97..9a77c4db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,12 +83,14 @@ jobs: with: python-version: ${{ matrix.python_version }} - - name: Install ansible base (devel branch) - run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check - - name: Install molecule and openshift dependencies run: pip install molecule yamllint openshift flake8 + - name: Install ansible base (devel branch) + run: | + pip uninstall ansible + pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + - name: Create default collection path symlink run: | mkdir -p /home/runner/.ansible diff --git a/.yamllint b/.yamllint index 39cf067b..45b68407 100644 --- a/.yamllint +++ b/.yamllint @@ -8,6 +8,7 @@ rules: brackets: max-spaces-inside: 1 level: error + document-start: disable line-length: disable truthy: disable indentation: From f4f4ec6fcf462089c066f13cf59250d7c41ccdaf Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Mon, 20 Jul 2020 16:31:49 -0500 Subject: [PATCH 51/88] Issue #167: More fixes, oops. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a77c4db..6b3923bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,7 +88,7 @@ jobs: - name: Install ansible base (devel branch) run: | - pip uninstall ansible + pip uninstall -y ansible pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check - name: Create default collection path symlink From 6c059bd2bca7ecf9ba7dd7d755eb13321d5da2a1 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Wed, 22 Jul 2020 09:14:23 +0530 Subject: [PATCH 52/88] helm_plugin and helm_plugin_info: new module (#154) Signed-off-by: Abhijeet Kasurde --- .../default/roles/helm/tasks/run_test.yml | 3 + .../roles/helm/tasks/tests_helm_plugin.yml | 84 ++++++ plugins/doc_fragments/helm_common_options.py | 34 +++ plugins/modules/helm.py | 19 +- plugins/modules/helm_info.py | 21 +- plugins/modules/helm_plugin.py | 242 ++++++++++++++++++ plugins/modules/helm_plugin_info.py | 167 ++++++++++++ 7 files changed, 534 insertions(+), 36 deletions(-) create mode 100644 molecule/default/roles/helm/tasks/tests_helm_plugin.yml create mode 100644 plugins/doc_fragments/helm_common_options.py create mode 100644 plugins/modules/helm_plugin.py create mode 100644 plugins/modules/helm_plugin_info.py diff --git a/molecule/default/roles/helm/tasks/run_test.yml b/molecule/default/roles/helm/tasks/run_test.yml index 42c54d09..0384a2e4 100644 --- a/molecule/default/roles/helm/tasks/run_test.yml +++ b/molecule/default/roles/helm/tasks/run_test.yml @@ -24,6 +24,9 @@ - from_repository - from_url +- name: Test helm plugin + include_tasks: tests_helm_plugin.yml + - name: Clean helm install file: path: "{{ item }}" diff --git a/molecule/default/roles/helm/tasks/tests_helm_plugin.yml b/molecule/default/roles/helm/tasks/tests_helm_plugin.yml new file mode 100644 index 00000000..720a06d5 --- /dev/null +++ b/molecule/default/roles/helm/tasks/tests_helm_plugin.yml @@ -0,0 +1,84 @@ +--- +- name: Install env plugin in check mode + helm_plugin: + binary_path: "{{ helm_binary }}" + namespace: "{{ helm_namespace }}" + state: present + plugin_path: https://github.com/adamreese/helm-env + register: check_install_env + check_mode: true + +- assert: + that: + - check_install_env.changed + +- name: Install env plugin + helm_plugin: + binary_path: "{{ helm_binary }}" + namespace: "{{ helm_namespace }}" + state: present + plugin_path: https://github.com/adamreese/helm-env + register: install_env + +- assert: + that: + - install_env.changed + +- name: Gather info about all plugin + helm_plugin_info: + binary_path: "{{ helm_binary }}" + namespace: "{{ helm_namespace }}" + register: plugin_info + +- assert: + that: + - plugin_info.plugin_list is defined + +- name: Install env plugin again + helm_plugin: + binary_path: "{{ helm_binary }}" + namespace: "{{ helm_namespace }}" + state: present + plugin_path: https://github.com/adamreese/helm-env + register: install_env + +- assert: + that: + - not install_env.changed + +- name: Uninstall env plugin in check mode + helm_plugin: + binary_path: "{{ helm_binary }}" + namespace: "{{ helm_namespace }}" + state: absent + plugin_name: env + register: check_uninstall_env + check_mode: true + +- assert: + that: + - check_uninstall_env.changed + +- name: Uninstall env plugin + helm_plugin: + binary_path: "{{ helm_binary }}" + namespace: "{{ helm_namespace }}" + state: absent + plugin_name: env + register: uninstall_env + +- assert: + that: + - uninstall_env.changed + +- name: Uninstall env plugin again + helm_plugin: + binary_path: "{{ helm_binary }}" + namespace: "{{ helm_namespace }}" + state: absent + plugin_name: env + register: uninstall_env + +- assert: + that: + - not uninstall_env.changed diff --git a/plugins/doc_fragments/helm_common_options.py b/plugins/doc_fragments/helm_common_options.py new file mode 100644 index 00000000..c2204004 --- /dev/null +++ b/plugins/doc_fragments/helm_common_options.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# Copyright: (c) 2020, Ansible Project +# Copyright: (c) 2020, Red Hat Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Options for common Helm modules + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class ModuleDocFragment(object): + + DOCUMENTATION = r''' +options: + binary_path: + description: + - The path of a helm binary to use. + required: false + type: path + context: + description: + - Helm option to specify which kubeconfig context to use. + - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_CONTEXT) will be used instead. + type: str + aliases: [ kube_context ] + kubeconfig: + description: + - Helm option to specify kubeconfig path to use. + - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_KUBECONFIG) will be used instead. + type: path + aliases: [ kubeconfig_path] +''' diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index a0972341..9045dc05 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -27,11 +27,6 @@ description: - Install, upgrade, delete packages with the Helm package manager. options: - binary_path: - description: - - The path of a helm binary to use. - required: false - type: path chart_ref: description: - chart_reference on chart repository. @@ -95,18 +90,6 @@ options: - Helm option to force reinstall, ignore on new install. default: False type: bool - kube_context: - description: - - Helm option to specify which kubeconfig context to use. - - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_CONTEXT) will be used instead. - type: str - aliases: [ context ] - kubeconfig_path: - description: - - Helm option to specify kubeconfig path to use. - - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_KUBECONFIG) will be used instead. - type: path - aliases: [ kubeconfig ] purge: description: - Remove the release from the store and make its name free for later use. @@ -132,6 +115,8 @@ options: type: bool default: False version_added: "0.11.1" +extends_documentation_fragment: + - community.kubernetes.helm_common_options ''' EXAMPLES = r''' diff --git a/plugins/modules/helm_info.py b/plugins/modules/helm_info.py index 31c6fab9..03ebdde3 100644 --- a/plugins/modules/helm_info.py +++ b/plugins/modules/helm_info.py @@ -26,11 +26,6 @@ description: - Get information (values, states, ...) from Helm package deployed inside the cluster. options: - binary_path: - description: - - The path of a helm binary to use. - required: false - type: path release_name: description: - Release name to manage. @@ -43,20 +38,8 @@ options: required: true type: str aliases: [ namespace ] - -#Helm options - kube_context: - description: - - Helm option to specify which kubeconfig context to use. - - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_CONTEXT) will be used instead. - type: str - aliases: [ context ] - kubeconfig_path: - description: - - Helm option to specify kubeconfig path to use. - - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_KUBECONFIG) will be used instead. - type: path - aliases: [ kubeconfig ] +extends_documentation_fragment: + - community.kubernetes.helm_common_options ''' EXAMPLES = r''' diff --git a/plugins/modules/helm_plugin.py b/plugins/modules/helm_plugin.py new file mode 100644 index 00000000..d93189c7 --- /dev/null +++ b/plugins/modules/helm_plugin.py @@ -0,0 +1,242 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2020, Ansible Project +# 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: helm_plugin +short_description: Manage Helm plugins +version_added: "0.11.0" +author: + - Abhijeet Kasurde (@Akasurde) +requirements: + - "helm (https://github.com/helm/helm/releases)" +description: + - Install, uninstall Helm plugins. +options: + release_namespace: + description: + - Kubernetes namespace where the helm plugin should be installed. + required: true + type: str + aliases: [ namespace ] + +#Helm options + state: + description: + - If C(state=present), Helm plugin will be installed. + - If C(state=absent), Helm plugin will be uninstalled. + choices: [ absent, present ] + default: present + type: str + plugin_name: + description: + - Name of Helm plugin. + - Required only if C(state=absent). + type: str + plugin_path: + description: + - Plugin path to a plugin on your local file system or a url of a remote VCS repo. + - If plugin path from file system is provided, make sure that tar is present on remote + machine and not on Ansible controller. + - Required only if C(state=present). + type: str +extends_documentation_fragment: + - community.kubernetes.helm_common_options +''' + +EXAMPLES = r''' +- name: Install Helm env plugin + community.kubernetes.helm_plugin: + plugin_path: https://github.com/adamreese/helm-env + state: present + +- name: Install Helm plugin from local filesystem + community.kubernetes.helm_plugin: + plugin_path: https://domain/path/to/plugin.tar.gz + state: present + +- name: Uninstall Helm env plugin + community.kubernetes.helm_plugin: + plugin_name: env + state: absent +''' + +RETURN = r''' +stdout: + type: str + description: Full `helm` command stdout, in case you want to display it or examine the event log + returned: always + sample: '' +stderr: + type: str + description: Full `helm` command stderr, in case you want to display it or examine the event log + returned: always + sample: '' +command: + type: str + description: Full `helm` command built by this module, in case you want to re-run the command outside the module or debug a problem. + returned: always + sample: helm plugin list ... +msg: + type: str + description: Info about successful command + returned: always + sample: "Plugin installed successfully" +rc: + type: int + description: Helm plugin command return code + returned: always + sample: 1 +''' + +from ansible.module_utils.basic import AnsibleModule, env_fallback + + +def main(): + module = AnsibleModule( + argument_spec=dict( + binary_path=dict(type='path'), + release_namespace=dict(type='str', required=True, aliases=['namespace']), + state=dict(type='str', default='present', choices=['present', 'absent']), + plugin_path=dict(type='str',), + plugin_name=dict(type='str',), + # Helm options + context=dict(type='str', aliases=['kube_context'], fallback=(env_fallback, ['K8S_AUTH_CONTEXT'])), + kubeconfig=dict(type='path', aliases=['kubeconfig_path'], fallback=(env_fallback, ['K8S_AUTH_KUBECONFIG'])), + ), + supports_check_mode=True, + required_if=[ + ("state", "present", ("plugin_path",)), + ("state", "absent", ("plugin_name",)), + ], + mutually_exclusive=[ + ['plugin_name', 'plugin_path'], + ], + ) + + bin_path = module.params.get('binary_path') + release_namespace = module.params.get('release_namespace') + state = module.params.get('state') + + # Helm options + kube_context = module.params.get('context') + kubeconfig_path = module.params.get('kubeconfig') + + if bin_path is not None: + helm_cmd_common = bin_path + else: + helm_cmd_common = 'helm' + + helm_cmd_common = module.get_bin_path(helm_cmd_common, required=True) + + helm_cmd_common += " plugin" + + if kube_context is not None: + helm_cmd_common += " --kube-context " + kube_context + + if kubeconfig_path is not None: + helm_cmd_common += " --kubeconfig " + kubeconfig_path + + helm_cmd_common += " --namespace=" + release_namespace + + if state == 'present': + helm_cmd_common += " install %s" % module.params.get('plugin_path') + if not module.check_mode: + rc, out, err = module.run_command(helm_cmd_common) + else: + rc, out, err = (0, '', '') + + if rc == 1 and 'plugin already exists' in err: + module.exit_json( + failed=False, + changed=False, + msg="Plugin already exists", + command=helm_cmd_common, + stdout=out, + stderr=err, + rc=rc + ) + elif rc == 0: + module.exit_json( + failed=False, + changed=True, + msg="Plugin installed successfully", + command=helm_cmd_common, + stdout=out, + stderr=err, + rc=rc, + ) + else: + module.fail_json( + msg="Failure when executing Helm command.", + command=helm_cmd_common, + stdout=out, + stderr=err, + rc=rc, + ) + elif state == 'absent': + plugin_name = module.params.get('plugin_name') + helm_plugin_list = helm_cmd_common + " list" + rc, out, err = module.run_command(helm_plugin_list) + if rc != 0 or (out == '' and err == ''): + module.fail_json( + msg="Failed to get Helm plugin info", + command=helm_plugin_list, + stdout=out, + stderr=err, + rc=rc, + ) + + if out: + found = False + for line in out.splitlines(): + if line.startswith("NAME"): + continue + name, dummy, dummy = line.split('\t', 3) + name = name.strip() + if name == plugin_name: + found = True + break + if found: + helm_uninstall_cmd = "%s uninstall %s" % (helm_cmd_common, plugin_name) + if not module.check_mode: + rc, out, err = module.run_command(helm_uninstall_cmd) + else: + rc, out, err = (0, '', '') + + if rc == 0: + module.exit_json( + changed=True, + msg="Plugin uninstalled successfully", + command=helm_uninstall_cmd, + stdout=out, + stderr=err, + rc=rc + ) + module.fail_json( + msg="Failed to get Helm plugin uninstall", + command=helm_uninstall_cmd, + stdout=out, + stderr=err, + rc=rc, + ) + else: + module.exit_json( + failed=False, + changed=False, + msg="Plugin not found or is already uninstalled", + command=helm_plugin_list, + stdout=out, + stderr=err, + rc=rc + ) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/helm_plugin_info.py b/plugins/modules/helm_plugin_info.py new file mode 100644 index 00000000..b9bf625d --- /dev/null +++ b/plugins/modules/helm_plugin_info.py @@ -0,0 +1,167 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2020, Ansible Project +# 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: helm_plugin_info +short_description: Gather information about Helm plugins +version_added: "0.11.0" +author: + - Abhijeet Kasurde (@Akasurde) +requirements: + - "helm (https://github.com/helm/helm/releases)" +description: + - Gather information about Helm plugins installed in namespace. +options: + release_namespace: + description: + - Kubernetes namespace where the helm plugins are installed. + required: true + type: str + aliases: [ namespace ] + +#Helm options + plugin_name: + description: + - Name of Helm plugin, to gather particular plugin info. + type: str +extends_documentation_fragment: + - community.kubernetes.helm_common_options +''' + +EXAMPLES = r''' +- name: Gather Helm plugin info + community.kubernetes.helm_plugin_info: + +- name: Gather Helm plugin info + community.kubernetes.helm_plugin_info: + plugin_name: env +''' + +RETURN = r''' +stdout: + type: str + description: Full `helm` command stdout, in case you want to display it or examine the event log + returned: always + sample: '' +stderr: + type: str + description: Full `helm` command stderr, in case you want to display it or examine the event log + returned: always + sample: '' +command: + type: str + description: Full `helm` command built by this module, in case you want to re-run the command outside the module or debug a problem. + returned: always + sample: helm plugin list ... +plugin_list: + type: list + description: Helm plugin dict inside a list + returned: always + sample: { + "name": "env", + "version": "0.1.0", + "description": "Print out the helm environment." + } +rc: + type: int + description: Helm plugin command return code + returned: always + sample: 1 +''' + +from ansible.module_utils.basic import AnsibleModule, env_fallback + + +def main(): + module = AnsibleModule( + argument_spec=dict( + binary_path=dict(type='path'), + release_namespace=dict(type='str', required=True, aliases=['namespace']), + plugin_name=dict(type='str',), + # Helm options + context=dict(type='str', aliases=['kube_context'], fallback=(env_fallback, ['K8S_AUTH_CONTEXT'])), + kubeconfig=dict(type='path', aliases=['kubeconfig_path'], fallback=(env_fallback, ['K8S_AUTH_KUBECONFIG'])), + ), + supports_check_mode=True, + ) + + bin_path = module.params.get('binary_path') + release_namespace = module.params.get('release_namespace') + + # Helm options + kube_context = module.params.get('context') + kubeconfig_path = module.params.get('kubeconfig') + + if bin_path is not None: + helm_cmd_common = bin_path + else: + helm_cmd_common = 'helm' + + helm_cmd_common = module.get_bin_path(helm_cmd_common, required=True) + + helm_cmd_common += " plugin" + + if kube_context is not None: + helm_cmd_common += " --kube-context " + kube_context + + if kubeconfig_path is not None: + helm_cmd_common += " --kubeconfig " + kubeconfig_path + + helm_cmd_common += " --namespace=" + release_namespace + + plugin_name = module.params.get('plugin_name') + helm_plugin_list = helm_cmd_common + " list" + rc, out, err = module.run_command(helm_plugin_list) + if rc != 0 or (out == '' and err == ''): + module.fail_json( + msg="Failed to get Helm plugin info", + command=helm_plugin_list, + stdout=out, + stderr=err, + rc=rc, + ) + + plugin_list = [] + if out: + for line in out.splitlines(): + if line.startswith("NAME"): + continue + name, version, description = line.split('\t', 3) + name = name.strip() + version = version.strip() + description = description.strip() + if plugin_name is None: + plugin_list.append({ + 'name': name, + 'version': version, + 'description': description, + }) + continue + + if plugin_name == name: + plugin_list.append({ + 'name': name, + 'version': version, + 'description': description, + }) + break + + module.exit_json( + changed=True, + command=helm_plugin_list, + stdout=out, + stderr=err, + rc=rc, + plugin_list=plugin_list, + ) + + +if __name__ == '__main__': + main() From 3aaf182c30b1f4f047e7697c06dbe652663a05fa Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Thu, 23 Jul 2020 10:52:26 +0530 Subject: [PATCH 53/88] k8s_exec: Return rc for the command executed (#158) k8s_exec now returns command return code in output. Fixes: #122 Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/122_k8s_exec_rc.yml | 2 + molecule/default/tasks/exec.yml | 13 ++++++ plugins/modules/k8s_exec.py | 54 ++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 changelogs/fragments/122_k8s_exec_rc.yml diff --git a/changelogs/fragments/122_k8s_exec_rc.yml b/changelogs/fragments/122_k8s_exec_rc.yml new file mode 100644 index 00000000..91d09b67 --- /dev/null +++ b/changelogs/fragments/122_k8s_exec_rc.yml @@ -0,0 +1,2 @@ +minor_changes: +- k8s_exec - return RC for the command executed (https://github.com/ansible-collections/community.kubernetes/issues/122). diff --git a/molecule/default/tasks/exec.yml b/molecule/default/tasks/exec.yml index 77a69f3e..5397ab95 100644 --- a/molecule/default/tasks/exec.yml +++ b/molecule/default/tasks/exec.yml @@ -43,6 +43,19 @@ that: - "'nameserver' in output.stdout" + - name: Check if rc is returned for the given command + k8s_exec: + namespace: "{{ exec_namespace }}" + pod: "{{ pod }}" + command: 'false' + register: command_status + ignore_errors: True + + - name: Check last command status + assert: + that: + - command_status.return_code != 0 + always: - name: "Cleanup namespace" k8s: diff --git a/plugins/modules/k8s_exec.py b/plugins/modules/k8s_exec.py index 8c7b29d6..f95bcd92 100644 --- a/plugins/modules/k8s_exec.py +++ b/plugins/modules/k8s_exec.py @@ -30,10 +30,13 @@ requirements: - "openshift == 0.4.3" - "PyYAML >= 3.11" +notes: +- Return code C(return_code) for the command executed is added in output in version 0.11.1. options: proxy: description: - - The URL of an HTTP proxy to use for the connection. Can also be specified via K8S_AUTH_PROXY environment variable. + - The URL of an HTTP proxy to use for the connection. + - Can also be specified via I(K8S_AUTH_PROXY) environment variable. - Please note that this module does not pick up typical proxy settings from the environment (e.g. HTTP_PROXY). type: str namespace: @@ -48,7 +51,8 @@ options: required: yes container: description: - - The name of the container in the pod to connect to. Defaults to only container if there is only one container in the pod. + - The name of the container in the pod to connect to. + - Defaults to only container if there is only one container in the pod. type: str required: no command: @@ -64,6 +68,19 @@ EXAMPLES = r''' namespace: myproject pod: zuul-scheduler command: zuul-scheduler full-reconfigure + +- name: Check RC status of command executed + community.kubernetes.k8s_exec: + namespace: myproject + pod: busybox-test + command: cmd_with_non_zero_exit_code + register: command_status + ignore_errors: True + +- name: Check last command status + debug: + msg: "cmd failed" + when: command_status.return_code != 0 ''' RETURN = r''' @@ -85,10 +102,23 @@ result: stderr_lines: description: The command stderr type: str + return_code: + description: The command status code + type: int ''' import copy import shlex +import traceback + +try: + import yaml + IMP_YAML = True +except ImportError: + IMP_YAML_ERR = traceback.format_exc() + IMP_YAML = False + +from ansible.module_utils.basic import missing_required_lib from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC @@ -113,6 +143,10 @@ class KubernetesExecCommand(KubernetesAnsibleModule): def main(): module = KubernetesExecCommand() + + if not IMP_YAML: + module.fail_json(msg=missing_required_lib("yaml"), exception=IMP_YAML_ERR) + # Load kubernetes.client.Configuration module.get_api_client() api = core_v1_api.CoreV1Api() @@ -131,15 +165,27 @@ def main(): stdin=False, tty=False, _preload_content=False, **optional_kwargs) - stdout, stderr = [], [] + stdout, stderr, rc = [], [], 0 while resp.is_open(): resp.update(timeout=1) if resp.peek_stdout(): stdout.append(resp.read_stdout()) if resp.peek_stderr(): stderr.append(resp.read_stderr()) + err = resp.read_channel(3) + err = yaml.safe_load(err) + if err['status'] == 'Success': + rc = 0 + else: + rc = int(err['details']['causes'][0]['message']) + module.exit_json( - changed=True, stdout="".join(stdout), stderr="".join(stderr)) + # Some command might change environment, but ultimately failing at end + changed=True, + stdout="".join(stdout), + stderr="".join(stderr), + return_code=rc + ) if __name__ == '__main__': From 9c0f7fe0bacd5da8d76a4e55540416cf5865af86 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Thu, 23 Jul 2020 11:06:56 -0500 Subject: [PATCH 54/88] Issue #167: Attempt installing ansible's stable-2.10 branch. --- .github/workflows/ci.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b3923bb..5b5ddc31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,10 +86,17 @@ jobs: - name: Install molecule and openshift dependencies run: pip install molecule yamllint openshift flake8 - - name: Install ansible base (devel branch) + - name: Install ansible base (2.10 branch) run: | pip uninstall -y ansible - pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + pip install https://github.com/ansible/ansible/archive/stable-2.10.tar.gz --disable-pip-version-check + + # The devel branch doesn't work with Molecule currently. + # See: https://github.com/ansible-community/molecule/issues/2757 + # - name: Install ansible base (devel branch) + # run: | + # pip uninstall -y ansible + # pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check - name: Create default collection path symlink run: | From bab4e387389b7614c104d373e779067bdfc1f70b Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Thu, 23 Jul 2020 11:15:35 -0500 Subject: [PATCH 55/88] Issue #167: Install ansible-base via pip with --pre. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b5ddc31..8e2e4f07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,10 +86,10 @@ jobs: - name: Install molecule and openshift dependencies run: pip install molecule yamllint openshift flake8 - - name: Install ansible base (2.10 branch) + - name: Install ansible base, latest release. run: | pip uninstall -y ansible - pip install https://github.com/ansible/ansible/archive/stable-2.10.tar.gz --disable-pip-version-check + pip install --pre ansible-base # The devel branch doesn't work with Molecule currently. # See: https://github.com/ansible-community/molecule/issues/2757 From 0473ac9fcc8a8f7d4d94d1db8d2ecf3ad8fd75c9 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Thu, 23 Jul 2020 11:22:35 -0500 Subject: [PATCH 56/88] Issue #167: Try Ansible's stable release. --- .github/workflows/ci.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e2e4f07..f28eef96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,12 +84,14 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install molecule and openshift dependencies - run: pip install molecule yamllint openshift flake8 + run: pip install ansible molecule yamllint openshift flake8 - - name: Install ansible base, latest release. - run: | - pip uninstall -y ansible - pip install --pre ansible-base + # The latest release doesn't work with Molecule currently. + # See: https://github.com/ansible-community/molecule/issues/2757 + # - name: Install ansible base, latest release. + # run: | + # pip uninstall -y ansible + # pip install --pre ansible-base # The devel branch doesn't work with Molecule currently. # See: https://github.com/ansible-community/molecule/issues/2757 From 9f099a43a7fb7e9e207c276603f6e70ec01a12a8 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Thu, 23 Jul 2020 11:33:56 -0500 Subject: [PATCH 57/88] Update docs links in README for plugins. --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 2cd04be0..2da39539 100644 --- a/README.md +++ b/README.md @@ -11,25 +11,25 @@ The collection includes a variety of Ansible content to help automate the manage Click on the name of a plugin or module to view that content's documentation: - **Connection Plugins**: - - [kubectl](https://docs.ansible.com/ansible/latest/plugins/connection/kubectl.html) + - [kubectl](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/kubectl_connection.html) - **Filter Plugins**: - [k8s_config_resource_name](https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#kubernetes-filters) - **Inventory Source**: - - [k8s](https://docs.ansible.com/ansible/latest/plugins/inventory/k8s.html) - - [openshift](https://docs.ansible.com/ansible/latest/plugins/inventory/openshift.html) + - [k8s](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_inventory.html) + - [openshift](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/openshift_inventory.html) - **Lookup Plugins**: - - [k8s](https://docs.ansible.com/ansible/latest/plugins/lookup/k8s.html) + - [k8s](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_lookup.html) - **Modules**: - - [k8s](https://docs.ansible.com/ansible/latest/modules/k8s_module.html) - - [k8s_auth](https://docs.ansible.com/ansible/latest/modules/k8s_auth_module.html) - - [k8s_exec](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/k8s_exec.py) - - [k8s_log](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/k8s_log.py) - - [k8s_info](https://docs.ansible.com/ansible/latest/modules/k8s_info_module.html) - - [k8s_scale](https://docs.ansible.com/ansible/latest/modules/k8s_scale_module.html) - - [k8s_service](https://docs.ansible.com/ansible/latest/modules/k8s_service_module.html) - - [helm](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/helm.py) - - [helm_info](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/helm_info.py) - - [helm_repository](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/helm_repository.py) + - [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_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) + - [k8s_scale](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_scale_module.html) + - [k8s_service](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_service_module.html) + - [helm](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/helm_module.html) + - [helm_info](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/helm_info_module.html) + - [helm_repository](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/helm_repository_module.html) ## Installation and Usage From cfcdf4afc39c17be8cc55a510b98bc0231149351 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Mon, 20 Jul 2020 15:50:12 -0500 Subject: [PATCH 58/88] Issue #165: Add plugin_routing information for deprecated plugins. --- meta/runtime.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/meta/runtime.yml b/meta/runtime.yml index bcce1985..0e5e3690 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -15,3 +15,29 @@ action_groups: - k8s_log - k8s_scale - k8s_service + +plugin_routing: + modules: + # k8s_facts was originally slated for removal in Ansible 2.13. + k8s_facts: + redirect: community.kubernetes.k8s_info + deprecation: + removal_version: 2.0.0 + warning_text: Use community.kubernetes.k8s_info instead. + k8s_raw: + tombstone: + removal_version: 0.1.0 + warning_text: The k8s_raw module was slated for deprecation in Ansible 2.10 and has been removed. Use community.kubernetes.k8s instead. + openshift_raw: + tombstone: + removal_version: 0.1.0 + warning_text: The openshift_raw module was slated for deprecation in Ansible 2.10 and has been removed. Use community.kubernetes.k8s instead. + openshift_scale: + tombstone: + removal_version: 0.1.0 + warning_text: The openshift_scale module was slated for deprecation in Ansible 2.10 and has been removed. Use community.kubernetes.k8s_scale instead. + lookup: + openshift: + tombstone: + removal_version: 0.1.0 + warning_text: The openshift lookup plugin was slated for deprecation in Ansible 2.10 and has been removed. Use community.kubernetes.k8s instead. From b51bbdf20078210f07281730b988e8acdb26c3eb Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 28 Jul 2020 09:37:14 -0500 Subject: [PATCH 59/88] Issue #171: Update changelog fragments for 1.0.0 release. --- changelogs/fragments/139-fix-manifest-ends-with-separator.yml | 3 ++- changelogs/fragments/140-kubeconfig-env.yaml | 4 ++++ changelogs/fragments/140_kubeconfig_env.yaml | 3 --- changelogs/fragments/141-helm-add-k8s-env-vars.yaml | 3 +++ changelogs/fragments/148-update-base-branch-main.yaml | 3 +++ changelogs/fragments/152-helm-context-aliases.yml | 4 ++++ changelogs/fragments/153-update-openshift-requirements.yaml | 3 +++ .../154-helm_plugin-helm_plugin_info-new-modules.yaml | 4 ++++ changelogs/fragments/155-ensure-check-mode-waits.yaml | 3 +++ changelogs/fragments/156-k8s_info-vars-example.yaml | 3 +++ changelogs/fragments/157-helm-create-namespace.yaml | 3 +++ changelogs/fragments/158-k8s_exec-return-rc.yaml | 3 +++ .../fragments/159-kubectl-redact-token-and-password.yaml | 3 +++ changelogs/fragments/168-test-stable-ansible.yaml | 3 +++ changelogs/fragments/helm_context_aliases.yml | 3 --- plugins/modules/helm_plugin.py | 2 +- plugins/modules/helm_plugin_info.py | 2 +- 17 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 changelogs/fragments/140-kubeconfig-env.yaml delete mode 100644 changelogs/fragments/140_kubeconfig_env.yaml create mode 100644 changelogs/fragments/141-helm-add-k8s-env-vars.yaml create mode 100644 changelogs/fragments/148-update-base-branch-main.yaml create mode 100644 changelogs/fragments/152-helm-context-aliases.yml create mode 100644 changelogs/fragments/153-update-openshift-requirements.yaml create mode 100644 changelogs/fragments/154-helm_plugin-helm_plugin_info-new-modules.yaml create mode 100644 changelogs/fragments/155-ensure-check-mode-waits.yaml create mode 100644 changelogs/fragments/156-k8s_info-vars-example.yaml create mode 100644 changelogs/fragments/157-helm-create-namespace.yaml create mode 100644 changelogs/fragments/158-k8s_exec-return-rc.yaml create mode 100644 changelogs/fragments/159-kubectl-redact-token-and-password.yaml create mode 100644 changelogs/fragments/168-test-stable-ansible.yaml delete mode 100644 changelogs/fragments/helm_context_aliases.yml diff --git a/changelogs/fragments/139-fix-manifest-ends-with-separator.yml b/changelogs/fragments/139-fix-manifest-ends-with-separator.yml index 0b2128aa..2742241d 100644 --- a/changelogs/fragments/139-fix-manifest-ends-with-separator.yml +++ b/changelogs/fragments/139-fix-manifest-ends-with-separator.yml @@ -1,2 +1,3 @@ +--- bugfixes: -- raw - handle condition when definition is none (https://github.com/ansible-collections/community.kubernetes/pull/139). + - raw - handle condition when definition is none (https://github.com/ansible-collections/community.kubernetes/pull/139). diff --git a/changelogs/fragments/140-kubeconfig-env.yaml b/changelogs/fragments/140-kubeconfig-env.yaml new file mode 100644 index 00000000..0d00dd7b --- /dev/null +++ b/changelogs/fragments/140-kubeconfig-env.yaml @@ -0,0 +1,4 @@ +--- +minor_changes: + - helm - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). + - helm_info - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). diff --git a/changelogs/fragments/140_kubeconfig_env.yaml b/changelogs/fragments/140_kubeconfig_env.yaml deleted file mode 100644 index 48a3e99a..00000000 --- a/changelogs/fragments/140_kubeconfig_env.yaml +++ /dev/null @@ -1,3 +0,0 @@ -minor_changes: -- helm - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). -- helm_info - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). diff --git a/changelogs/fragments/141-helm-add-k8s-env-vars.yaml b/changelogs/fragments/141-helm-add-k8s-env-vars.yaml new file mode 100644 index 00000000..e6518d49 --- /dev/null +++ b/changelogs/fragments/141-helm-add-k8s-env-vars.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - helm - Add support for K8S_AUTH_CONTEXT, K8S_AUTH_KUBECONFIG env (https://github.com/ansible-collections/community.kubernetes/pull/141). diff --git a/changelogs/fragments/148-update-base-branch-main.yaml b/changelogs/fragments/148-update-base-branch-main.yaml new file mode 100644 index 00000000..268200c5 --- /dev/null +++ b/changelogs/fragments/148-update-base-branch-main.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Update base branch to 'main' (https://github.com/ansible-collections/community.kubernetes/issues/148). diff --git a/changelogs/fragments/152-helm-context-aliases.yml b/changelogs/fragments/152-helm-context-aliases.yml new file mode 100644 index 00000000..424bc73e --- /dev/null +++ b/changelogs/fragments/152-helm-context-aliases.yml @@ -0,0 +1,4 @@ +--- +minor_changes: + - helm - add aliases context for kube_context. + - helm_info - add aliases context for kube_context. diff --git a/changelogs/fragments/153-update-openshift-requirements.yaml b/changelogs/fragments/153-update-openshift-requirements.yaml new file mode 100644 index 00000000..502449b0 --- /dev/null +++ b/changelogs/fragments/153-update-openshift-requirements.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Update openshift requirements in k8s module doc (https://github.com/ansible-collections/community.kubernetes/pull/153). diff --git a/changelogs/fragments/154-helm_plugin-helm_plugin_info-new-modules.yaml b/changelogs/fragments/154-helm_plugin-helm_plugin_info-new-modules.yaml new file mode 100644 index 00000000..33a550f8 --- /dev/null +++ b/changelogs/fragments/154-helm_plugin-helm_plugin_info-new-modules.yaml @@ -0,0 +1,4 @@ +--- +major_changes: + - helm_plugin - new module to manage Helm plugins (https://github.com/ansible-collections/community.kubernetes/pull/154). + - helm_plugin_info - new modules to gather information about Helm plugins (https://github.com/ansible-collections/community.kubernetes/pull/154). diff --git a/changelogs/fragments/155-ensure-check-mode-waits.yaml b/changelogs/fragments/155-ensure-check-mode-waits.yaml new file mode 100644 index 00000000..5a68c343 --- /dev/null +++ b/changelogs/fragments/155-ensure-check-mode-waits.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Ensure check mode results are as expected (https://github.com/ansible-collections/community.kubernetes/pull/155). diff --git a/changelogs/fragments/156-k8s_info-vars-example.yaml b/changelogs/fragments/156-k8s_info-vars-example.yaml new file mode 100644 index 00000000..0ebe4318 --- /dev/null +++ b/changelogs/fragments/156-k8s_info-vars-example.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - k8s_info - Update example using vars (https://github.com/ansible-collections/community.kubernetes/pull/156). diff --git a/changelogs/fragments/157-helm-create-namespace.yaml b/changelogs/fragments/157-helm-create-namespace.yaml new file mode 100644 index 00000000..8e3ace60 --- /dev/null +++ b/changelogs/fragments/157-helm-create-namespace.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - helm - Allow creating namespaces with Helm (https://github.com/ansible-collections/community.kubernetes/pull/157). diff --git a/changelogs/fragments/158-k8s_exec-return-rc.yaml b/changelogs/fragments/158-k8s_exec-return-rc.yaml new file mode 100644 index 00000000..f8a10fb7 --- /dev/null +++ b/changelogs/fragments/158-k8s_exec-return-rc.yaml @@ -0,0 +1,3 @@ +--- +major_changes: + - k8s_exec - Return rc for the command executed (https://github.com/ansible-collections/community.kubernetes/pull/158). diff --git a/changelogs/fragments/159-kubectl-redact-token-and-password.yaml b/changelogs/fragments/159-kubectl-redact-token-and-password.yaml new file mode 100644 index 00000000..b58ffd97 --- /dev/null +++ b/changelogs/fragments/159-kubectl-redact-token-and-password.yaml @@ -0,0 +1,3 @@ +--- +security_fixes: + - kubectl - redacted token and password from console log (https://github.com/ansible-collections/community.kubernetes/pull/159). diff --git a/changelogs/fragments/168-test-stable-ansible.yaml b/changelogs/fragments/168-test-stable-ansible.yaml new file mode 100644 index 00000000..d05a4b0a --- /dev/null +++ b/changelogs/fragments/168-test-stable-ansible.yaml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Test against stable ansible branch so molecule tests work (https://github.com/ansible-collections/community.kubernetes/pull/168). diff --git a/changelogs/fragments/helm_context_aliases.yml b/changelogs/fragments/helm_context_aliases.yml deleted file mode 100644 index 02a0e909..00000000 --- a/changelogs/fragments/helm_context_aliases.yml +++ /dev/null @@ -1,3 +0,0 @@ -minor_changes: -- helm - add aliases context for kube_context. -- helm_info - add aliases context for kube_context. diff --git a/plugins/modules/helm_plugin.py b/plugins/modules/helm_plugin.py index d93189c7..a212394f 100644 --- a/plugins/modules/helm_plugin.py +++ b/plugins/modules/helm_plugin.py @@ -11,7 +11,7 @@ DOCUMENTATION = r''' --- module: helm_plugin short_description: Manage Helm plugins -version_added: "0.11.0" +version_added: "1.0.0" author: - Abhijeet Kasurde (@Akasurde) requirements: diff --git a/plugins/modules/helm_plugin_info.py b/plugins/modules/helm_plugin_info.py index b9bf625d..951f1ed9 100644 --- a/plugins/modules/helm_plugin_info.py +++ b/plugins/modules/helm_plugin_info.py @@ -11,7 +11,7 @@ DOCUMENTATION = r''' --- module: helm_plugin_info short_description: Gather information about Helm plugins -version_added: "0.11.0" +version_added: "1.0.0" author: - Abhijeet Kasurde (@Akasurde) requirements: From 1ef28bcd73976090ce5b0ae8d7ce355e2dcd1184 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 28 Jul 2020 09:43:15 -0500 Subject: [PATCH 60/88] Issue #171: Update changelog and make sure things are ready for 1.0.0 release. --- CHANGELOG.rst | 42 +++++++++++++++++++++++++++++++ README.md | 2 +- changelogs/changelog.yaml | 49 +++++++++++++++++++++++++++++++++++++ galaxy.yml | 2 +- plugins/modules/k8s_exec.py | 2 +- 5 files changed, 94 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f14d8624..d5940f03 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,48 @@ Kubernetes Collection Release Notes .. contents:: Topics +v1.0.0 +====== + +Major Changes +------------- + +- helm_plugin - new module to manage Helm plugins (https://github.com/ansible-collections/community.kubernetes/pull/154). +- helm_plugin_info - new modules to gather information about Helm plugins (https://github.com/ansible-collections/community.kubernetes/pull/154). +- k8s_exec - Return rc for the command executed (https://github.com/ansible-collections/community.kubernetes/pull/158). + +Minor Changes +------------- + +- Ensure check mode results are as expected (https://github.com/ansible-collections/community.kubernetes/pull/155). +- Update base branch to 'main' (https://github.com/ansible-collections/community.kubernetes/issues/148). +- helm - Add support for K8S_AUTH_CONTEXT, K8S_AUTH_KUBECONFIG env (https://github.com/ansible-collections/community.kubernetes/pull/141). +- helm - Allow creating namespaces with Helm (https://github.com/ansible-collections/community.kubernetes/pull/157). +- helm - add aliases context for kube_context. +- helm - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). +- helm_info - add aliases context for kube_context. +- helm_info - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). +- k8s_exec - return RC for the command executed (https://github.com/ansible-collections/community.kubernetes/issues/122). +- k8s_info - Update example using vars (https://github.com/ansible-collections/community.kubernetes/pull/156). + +Security Fixes +-------------- + +- kubectl - connection plugin now redact kubectl_token and kubectl_password in console log (https://github.com/ansible-collections/community.kubernetes/issues/65). +- kubectl - redacted token and password from console log (https://github.com/ansible-collections/community.kubernetes/pull/159). + +Bugfixes +-------- + +- Test against stable ansible branch so molecule tests work (https://github.com/ansible-collections/community.kubernetes/pull/168). +- Update openshift requirements in k8s module doc (https://github.com/ansible-collections/community.kubernetes/pull/153). + +New Modules +----------- + +- helm_plugin - Manage Helm plugins +- helm_plugin_info - Gather information about Helm plugins + v0.11.1 ======= diff --git a/README.md b/README.md index 2da39539..30c25640 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ You can also include it in a `requirements.yml` file and install it via `ansible --- collections: - name: community.kubernetes - version: 0.11.1 + version: 1.0.0 ``` ### Installing the OpenShift Python Library diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 79356fe3..4d4331cb 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -137,3 +137,52 @@ releases: fragments: - 4-k8s-prepare-collection-for-release.yaml release_date: '2020-02-05' + 1.0.0: + changes: + bugfixes: + - Test against stable ansible branch so molecule tests work (https://github.com/ansible-collections/community.kubernetes/pull/168). + - Update openshift requirements in k8s module doc (https://github.com/ansible-collections/community.kubernetes/pull/153). + major_changes: + - helm_plugin - new module to manage Helm plugins (https://github.com/ansible-collections/community.kubernetes/pull/154). + - helm_plugin_info - new modules to gather information about Helm plugins (https://github.com/ansible-collections/community.kubernetes/pull/154). + - k8s_exec - Return rc for the command executed (https://github.com/ansible-collections/community.kubernetes/pull/158). + minor_changes: + - Ensure check mode results are as expected (https://github.com/ansible-collections/community.kubernetes/pull/155). + - Update base branch to 'main' (https://github.com/ansible-collections/community.kubernetes/issues/148). + - helm - Add support for K8S_AUTH_CONTEXT, K8S_AUTH_KUBECONFIG env (https://github.com/ansible-collections/community.kubernetes/pull/141). + - helm - Allow creating namespaces with Helm (https://github.com/ansible-collections/community.kubernetes/pull/157). + - helm - add aliases context for kube_context. + - helm - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment + variable (https://github.com/ansible-collections/community.kubernetes/issues/140). + - helm_info - add aliases context for kube_context. + - helm_info - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment + variable (https://github.com/ansible-collections/community.kubernetes/issues/140). + - k8s_exec - return RC for the command executed (https://github.com/ansible-collections/community.kubernetes/issues/122). + - k8s_info - Update example using vars (https://github.com/ansible-collections/community.kubernetes/pull/156). + security_fixes: + - kubectl - connection plugin now redact kubectl_token and kubectl_password + in console log (https://github.com/ansible-collections/community.kubernetes/issues/65). + - kubectl - redacted token and password from console log (https://github.com/ansible-collections/community.kubernetes/pull/159). + fragments: + - 122_k8s_exec_rc.yml + - 140-kubeconfig-env.yaml + - 141-helm-add-k8s-env-vars.yaml + - 148-update-base-branch-main.yaml + - 152-helm-context-aliases.yml + - 153-update-openshift-requirements.yaml + - 154-helm_plugin-helm_plugin_info-new-modules.yaml + - 155-ensure-check-mode-waits.yaml + - 156-k8s_info-vars-example.yaml + - 157-helm-create-namespace.yaml + - 158-k8s_exec-return-rc.yaml + - 159-kubectl-redact-token-and-password.yaml + - 168-test-stable-ansible.yaml + - 65_kubectl.yml + modules: + - description: Manage Helm plugins + name: helm_plugin + namespace: '' + - description: Gather information about Helm plugins + name: helm_plugin_info + namespace: '' + release_date: '2020-07-28' diff --git a/galaxy.yml b/galaxy.yml index f3e4dfd9..fbebf31b 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -26,7 +26,7 @@ tags: - openshift - okd - cluster -version: 0.11.1 +version: 1.0.0 build_ignore: - .DS_Store - '*.tar.gz' diff --git a/plugins/modules/k8s_exec.py b/plugins/modules/k8s_exec.py index f95bcd92..4c850764 100644 --- a/plugins/modules/k8s_exec.py +++ b/plugins/modules/k8s_exec.py @@ -31,7 +31,7 @@ requirements: - "PyYAML >= 3.11" notes: -- Return code C(return_code) for the command executed is added in output in version 0.11.1. +- Return code C(return_code) for the command executed is added in output in version 1.0.0. options: proxy: description: From 81494e2ae22b34eae834e3c823c9fe5f4a9ba622 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 28 Jul 2020 09:46:44 -0500 Subject: [PATCH 61/88] Issue #171: Update fragment for PR #152 to include link. --- CHANGELOG.rst | 4 ++-- changelogs/changelog.yaml | 4 ++-- changelogs/fragments/152-helm-context-aliases.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d5940f03..8a9bd301 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -22,9 +22,9 @@ Minor Changes - Update base branch to 'main' (https://github.com/ansible-collections/community.kubernetes/issues/148). - helm - Add support for K8S_AUTH_CONTEXT, K8S_AUTH_KUBECONFIG env (https://github.com/ansible-collections/community.kubernetes/pull/141). - helm - Allow creating namespaces with Helm (https://github.com/ansible-collections/community.kubernetes/pull/157). -- helm - add aliases context for kube_context. +- helm - add aliases context for kube_context (https://github.com/ansible-collections/community.kubernetes/pull/152). - helm - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). -- helm_info - add aliases context for kube_context. +- helm_info - add aliases context for kube_context (https://github.com/ansible-collections/community.kubernetes/pull/152). - helm_info - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). - k8s_exec - return RC for the command executed (https://github.com/ansible-collections/community.kubernetes/issues/122). - k8s_info - Update example using vars (https://github.com/ansible-collections/community.kubernetes/pull/156). diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 4d4331cb..65d8e949 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -151,10 +151,10 @@ releases: - Update base branch to 'main' (https://github.com/ansible-collections/community.kubernetes/issues/148). - helm - Add support for K8S_AUTH_CONTEXT, K8S_AUTH_KUBECONFIG env (https://github.com/ansible-collections/community.kubernetes/pull/141). - helm - Allow creating namespaces with Helm (https://github.com/ansible-collections/community.kubernetes/pull/157). - - helm - add aliases context for kube_context. + - helm - add aliases context for kube_context (https://github.com/ansible-collections/community.kubernetes/pull/152). - helm - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). - - helm_info - add aliases context for kube_context. + - helm_info - add aliases context for kube_context (https://github.com/ansible-collections/community.kubernetes/pull/152). - helm_info - add support for K8S_AUTH_KUBECONFIG and K8S_AUTH_CONTEXT environment variable (https://github.com/ansible-collections/community.kubernetes/issues/140). - k8s_exec - return RC for the command executed (https://github.com/ansible-collections/community.kubernetes/issues/122). diff --git a/changelogs/fragments/152-helm-context-aliases.yml b/changelogs/fragments/152-helm-context-aliases.yml index 424bc73e..4a3d0876 100644 --- a/changelogs/fragments/152-helm-context-aliases.yml +++ b/changelogs/fragments/152-helm-context-aliases.yml @@ -1,4 +1,4 @@ --- minor_changes: - - helm - add aliases context for kube_context. - - helm_info - add aliases context for kube_context. + - helm - add aliases context for kube_context (https://github.com/ansible-collections/community.kubernetes/pull/152). + - helm_info - add aliases context for kube_context (https://github.com/ansible-collections/community.kubernetes/pull/152). From e29d4f1d1fdbfe0d490b5c9378dbda336b383c9d Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 28 Jul 2020 10:35:24 -0500 Subject: [PATCH 62/88] Issue #171: Add links for new modules in README. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 30c25640..786f544e 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ Click on the name of a plugin or module to view that content's documentation: - [k8s_service](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/k8s_service_module.html) - [helm](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/helm_module.html) - [helm_info](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/helm_info_module.html) + - [helm_plugin](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/helm_plugin.py) + - [helm_plugin_info](https://github.com/ansible-collections/community.kubernetes/blob/main/plugins/modules/helm_plugin_info.py) - [helm_repository](https://docs.ansible.com/ansible/2.10/collections/community/kubernetes/helm_repository_module.html) ## Installation and Usage From 666b75eba4d11e4d20b25df74b07acfe8cf7a593 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 5 Aug 2020 23:27:24 -0500 Subject: [PATCH 63/88] Fix typo in Readme. (#182) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 786f544e..6f4ebe0a 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Click on the name of a plugin or module to view that content's documentation: ### Installing the Collection from Ansible Galaxy -Before using the Kuberentes collection, you need to install it with the Ansible Galaxy CLI: +Before using the Kubernetes collection, you need to install it with the Ansible Galaxy CLI: ansible-galaxy collection install community.kubernetes From 4f33ba7b39a39965de587e4c3b9132cbe621479d Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Tue, 11 Aug 2020 11:12:53 +0530 Subject: [PATCH 64/88] raw: Handle exception raised by underlying APIs (#180) kind can be provided by number of ways. It is diffcult to find all cases. So, handle exceptions raised by underlying APIs and provide good error message to user. Fixes: ansible/ansible#63652 Signed-off-by: Abhijeet Kasurde --- plugins/module_utils/raw.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index 47c7443c..bae8f6ea 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -27,6 +27,7 @@ import traceback from ansible.module_utils.basic import missing_required_lib from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC from ansible.module_utils.six import string_types +from ansible.module_utils._text import to_native from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule from ansible.module_utils.common.dict_transformations import dict_merge @@ -175,7 +176,7 @@ class KubernetesRawModule(KubernetesAnsibleModule): continue kind = definition.get('kind', self.kind) api_version = definition.get('apiVersion', self.api_version) - if kind.endswith('List'): + if kind and kind.endswith('List'): resource = self.find_resource(kind, api_version, fail=False) flattened_definitions.extend(self.flatten_list_kind(resource, definition)) else: @@ -269,6 +270,9 @@ class KubernetesRawModule(KubernetesAnsibleModule): except DynamicApiError as exc: self.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc.body), error=exc.status, status=exc.status, reason=exc.reason) + except Exception as exc: + self.fail_json(msg='Failed to retrieve requested object: {0}'.format(to_native(exc)), + error='', status='', reason='') if state == 'absent': result['method'] = "delete" @@ -422,6 +426,12 @@ class KubernetesRawModule(KubernetesAnsibleModule): msg += "\n" + "\n ".join(self.warnings) error = dict(msg=msg, error=exc.status, status=exc.status, reason=exc.reason, warnings=self.warnings) return None, error + except Exception as exc: + msg = "Failed to patch object: {0}".format(exc) + if self.warnings: + msg += "\n" + "\n ".join(self.warnings) + error = dict(msg=msg, error=to_native(exc), status='', reason='', warnings=self.warnings) + return None, error def create_project_request(self, definition): definition['kind'] = 'ProjectRequest' From f58e6489cea1d182f087a467ae09265fc4b7bc26 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Wed, 12 Aug 2020 17:57:44 +0530 Subject: [PATCH 65/88] Add contrib page Fixes: #120 Signed-off-by: Abhijeet Kasurde --- CONTRIBUTING.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 ++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..0fcae83f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,65 @@ +# Contributing + +## Getting Started + +General information about setting up your Python environment, testing modules, +Ansible coding styles, and more can be found in the [Ansible Community Guide]( +https://docs.ansible.com/ansible/latest/community/index.html). + + +## Kubernetes Collections + +### community.kubernetes + +This collection contains modules and plugins contributed and maintained by the Ansible Kubernetes +community. + +New modules and plugins developed by the community should be proposed to `community.kubernetes`. + +## Submitting Issues +All software has bugs, and the `community.kubernetes` collection is no exception. When you find a bug, +you can help tremendously by [telling us about it](https://github.com/ansible-collections/community.kubernetes/issues/new/choose). + +If you should discover that the bug you're trying to file already exists in an issue, +you can help by verifying the behavior of the reported bug with a comment in that +issue, or by reporting any additional information. + +## Pull Requests + +All modules MUST have integration tests for new features. +Bug fixes for modules that currently have integration tests SHOULD have tests added. +New modules should be submitted to the [community.kubernetes](https://github.com/ansible-collections/community.kubernetes) collection and MUST have integration tests. + +Expected test criteria: +* Resource creation under check mode +* Resource creation +* Resource creation again (idempotency) under check mode +* Resource creation again (idempotency) +* Resource modification under check mode +* Resource modification +* Resource modification again (idempotency) under check mode +* Resource modification again (idempotency) +* Resource deletion under check mode +* Resource deletion +* Resource deletion (of a non-existent resource) under check mode +* Resource deletion (of a non-existent resource) + +Where modules have multiple parameters we recommend running through the 4-step modification cycle for each parameter the module accepts, as well as a modification cycle where as most, if not all, parameters are modified at the same time. + +For general information on running the integration tests see the +[Integration Tests page of the Module Development Guide](https://docs.ansible.com/ansible/devel/dev_guide/testing_integration.html#testing-integration), +especially the section on configuration for cloud tests. For questions about writing tests the Ansible Kubernetes community can be found on Freenode IRC as detailed below. + + +### Code of Conduct +The `community.kubernetes` collection follows the Ansible project's +[Code of Conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html). +Please read and familiarize yourself with this document. + +### IRC +Our IRC channels may require you to register your nickname. If you receive an error when you connect, see +[Freenode's Nickname Registration guide](https://freenode.net/kb/answer/registration) for instructions. + +The `#ansible-kubernetes` channel on Freenode IRC is the main and official place to discuss use and development of the `community.kubernetes` collection. + +For more information about Ansible's Kubernetes integration, browse the resources in the [Kubernetes Working Group](https://github.com/ansible/community/wiki/Kubernetes) Community wiki page. diff --git a/README.md b/README.md index 786f544e..4c1c9808 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Click on the name of a plugin or module to view that content's documentation: ### Installing the Collection from Ansible Galaxy -Before using the Kuberentes collection, you need to install it with the Ansible Galaxy CLI: +Before using the Kubernetes collection, you need to install it with the Ansible Galaxy CLI: ansible-galaxy collection install community.kubernetes @@ -128,6 +128,8 @@ For documentation on how to use individual modules and other content included in If you want to develop new content for this collection or improve what's already here, the easiest way to work on the collection is to clone it into one of the configured [`COLLECTIONS_PATHS`](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths), and work on it there. +See [Contributing to community.kubernetes](CONTRIBUTING.md). + ### Testing with `ansible-test` The `tests` directory contains configuration for running sanity and integration tests using [`ansible-test`](https://docs.ansible.com/ansible/latest/dev_guide/testing_integration.html). From 4eea323bb601e91bea605d960c2a3b03d13c448b Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 18 Aug 2020 10:26:00 -0500 Subject: [PATCH 66/88] Issue #43: Update README to reflect new Zuul automated tag build and push. --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index 786f544e..9c231cf5 100644 --- a/README.md +++ b/README.md @@ -146,10 +146,8 @@ There are also integration tests in the `molecule` directory which are meant to ## Publishing New Versions -The current process for publishing new versions of the Kubernetes Collection is manual, and requires a user who has access to the `community.kubernetes` namespace on Ansible Galaxy to publish the build artifact. See [Issue #43](https://github.com/ansible-collections/community.kubernetes/issues/43) for progress in automating this process. +Releases are automatically built and pushed to Ansible Galaxy for any new tag. Before tagging a release, make sure to do the following: - 1. Ensure you're running Ansible from devel, so the [`build_ignore` key](https://github.com/ansible/ansible/issues/67130) in `galaxy.yml` is used. - 1. Run `git clean -x -d -f` in this repository's directory to clean out any extra files which should not be included. 1. Update `galaxy.yml` and this README's `requirements.yml` example with the new `version` for the collection. 1. Update the CHANGELOG: 1. Make sure you have [`antsibull-changelog`](https://pypi.org/project/antsibull-changelog/) installed. @@ -157,12 +155,6 @@ The current process for publishing new versions of the Kubernetes Collection is 1. Run `antsibull-changelog release`. 1. Commit the changes and create a PR with the changes. Wait for tests to pass, then merge it once they have. 1. Tag the version in Git and push to GitHub. - 1. Run the following commands to build and release the new version on Galaxy: - - ``` - ansible-galaxy collection build - ansible-galaxy collection publish ./community-kubernetes-$VERSION_HERE.tar.gz - ``` After the version is published, verify it exists on the [Kubernetes Collection Galaxy page](https://galaxy.ansible.com/community/kubernetes). From 7acd460bdccd00fc67960870e21057c7db03b111 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Tue, 18 Aug 2020 10:46:35 -0500 Subject: [PATCH 67/88] Issue #53: Add probot/stale bot configuration to ID and close stale issues. --- .github/stale.yml | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..4818ef4d --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,60 @@ +--- +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 90 + +# Number of days of inactivity before an Issue or Pull Request with the stale +# label is closed. Set to false to disable. If disabled, issues still need to be +# closed manually, but will remain marked as stale. +daysUntilClose: 30 + +# Only issues or pull requests with all of these labels are check if stale. +# Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set +# to `[]` to disable +exemptLabels: + - pinned + - security + - planned + - priority/critical + - verified + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: true + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: lifecycle/stale + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +pulls: + markComment: |- + PRs go stale after 90 days of inactivity. + If there is no further activity, the PR will be closed in another 30 days. + + unmarkComment: >- + This pull request is no longer stale. + + closeComment: >- + This pull request has been closed due to inactivity. + +issues: + markComment: |- + Issues go stale after 90 days of inactivity. + If there is no further activity, the issue will be closed in another 30 days. + + unmarkComment: >- + This issue is no longer stale. + + closeComment: >- + This issue has been closed due to inactivity. From ab77b79f9ca6175ff96a8316d451e23abc058729 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 24 Aug 2020 11:06:20 +0530 Subject: [PATCH 68/88] k8s_info: Update documentation * Used name_option doc_fragments * Updated doc formatting * Updated k8s_info example for custom resource Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/202_k8s_info.yml | 2 ++ plugins/doc_fragments/k8s_name_options.py | 32 +++++++++++---------- plugins/modules/k8s_info.py | 34 ++++++++--------------- 3 files changed, 32 insertions(+), 36 deletions(-) create mode 100644 changelogs/fragments/202_k8s_info.yml diff --git a/changelogs/fragments/202_k8s_info.yml b/changelogs/fragments/202_k8s_info.yml new file mode 100644 index 00000000..78f26256 --- /dev/null +++ b/changelogs/fragments/202_k8s_info.yml @@ -0,0 +1,2 @@ +minor_changes: +- k8s_info - update custom resource example (https://github.com/ansible-collections/community.kubernetes/issues/202). diff --git a/plugins/doc_fragments/k8s_name_options.py b/plugins/doc_fragments/k8s_name_options.py index 58840d55..fe4e5c47 100644 --- a/plugins/doc_fragments/k8s_name_options.py +++ b/plugins/doc_fragments/k8s_name_options.py @@ -15,9 +15,10 @@ class ModuleDocFragment(object): options: api_version: description: - - Use to specify the API version. Use to create, delete, or discover an object without providing a full - resource definition. Use in conjunction with I(kind), I(name), and I(namespace) to identify a - specific object. If I(resource definition) is provided, the I(apiVersion) from the I(resource_definition) + - Use to specify the API version. + - Use to create, delete, or discover an object without providing a full resource definition. + - Use in conjunction with I(kind), I(name), and I(namespace) to identify a specific object. + - If I(resource definition) is provided, the I(apiVersion) value from the I(resource_definition) will override this option. type: str default: v1 @@ -26,23 +27,26 @@ options: - version kind: description: - - Use to specify an object model. Use to create, delete, or discover an object without providing a full - resource definition. Use in conjunction with I(api_version), I(name), and I(namespace) to identify a - specific object. If I(resource definition) is provided, the I(kind) from the I(resource_definition) + - Use to specify an object model. + - Use to create, delete, or discover an object without providing a full resource definition. + - Use in conjunction with I(api_version), I(name), and I(namespace) to identify a specific object. + - If I(resource definition) is provided, the I(kind) value from the I(resource_definition) will override this option. type: str name: description: - - Use to specify an object name. Use to create, delete, or discover an object without providing a full - resource definition. Use in conjunction with I(api_version), I(kind) and I(namespace) to identify a - specific object. If I(resource definition) is provided, the I(metadata.name) value from the - I(resource_definition) will override this option. + - Use to specify an object name. + - Use to create, delete, or discover an object without providing a full resource definition. + - Use in conjunction with I(api_version), I(kind) and I(namespace) to identify a specific object. + - If I(resource definition) is provided, the I(metadata.name) value from the I(resource_definition) + will override this option. type: str namespace: description: - - Use to specify an object namespace. Useful when creating, deleting, or discovering an object without - providing a full resource definition. Use in conjunction with I(api_version), I(kind), and I(name) - to identify a specific object. If I(resource definition) is provided, the I(metadata.namespace) value - from the I(resource_definition) will override this option. + - Use to specify an object namespace. + - Useful when creating, deleting, or discovering an object without providing a full resource definition. + - Use in conjunction with I(api_version), I(kind), and I(name) to identify a specific object. + - If I(resource definition) is provided, the I(metadata.namespace) value from the I(resource_definition) + will override this option. type: str ''' diff --git a/plugins/modules/k8s_info.py b/plugins/modules/k8s_info.py index 0fc6ab94..2811f534 100644 --- a/plugins/modules/k8s_info.py +++ b/plugins/modules/k8s_info.py @@ -25,31 +25,15 @@ description: - This module was called C(k8s_facts) before Ansible 2.9. The usage did not change. options: - api_version: - description: - - Use to specify the API version. in conjunction with I(kind), I(name), and I(namespace) to identify a - specific object. - default: v1 - aliases: - - api - - version - type: str kind: description: - - Use to specify an object model. Use in conjunction with I(api_version), I(name), and I(namespace) to identify a - specific object. - required: yes - type: str - name: - description: - - Use to specify an object name. Use in conjunction with I(api_version), I(kind) and I(namespace) to identify a - specific object. - type: str - namespace: - description: - - Use to specify an object namespace. Use in conjunction with I(api_version), I(kind), and I(name) - to identify a specific object. + - Use to specify an object model. + - Use to create, delete, or discover an object without providing a full resource definition. + - Use in conjunction with I(api_version), I(name), and I(namespace) to identify a specific object. + - If I(resource definition) is provided, the I(kind) value from the I(resource_definition) + will override this option. type: str + required: True label_selectors: description: List of label selectors to use to filter results type: list @@ -61,6 +45,7 @@ options: extends_documentation_fragment: - community.kubernetes.k8s_auth_options + - community.kubernetes.k8s_name_options requirements: - "python >= 2.7" @@ -109,6 +94,11 @@ EXAMPLES = r''' kind: Pod field_selectors: - status.phase=Running + +- name: List custom objects created using CRD + community.kubernetes.k8s_info: + kind: MyCustomObject + api_version: "stable.example.com/v1" ''' RETURN = r''' From d39fcfc2d8692e41cb0eef6100715c7a8e966355 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Wed, 26 Aug 2020 10:22:47 +0530 Subject: [PATCH 69/88] k8s_*: Add support for vaulted kubeconfig and src (#193) --- plugins/action/k8s.py | 1 + plugins/action/k8s_auth.py | 1 + plugins/action/k8s_exec.py | 1 + plugins/action/k8s_info.py | 82 +++++++++++++++++++++++++++++++++++ plugins/action/k8s_log.py | 1 + plugins/action/k8s_scale.py | 1 + plugins/action/k8s_service.py | 1 + 7 files changed, 88 insertions(+) create mode 120000 plugins/action/k8s.py create mode 120000 plugins/action/k8s_auth.py create mode 120000 plugins/action/k8s_exec.py create mode 100644 plugins/action/k8s_info.py create mode 120000 plugins/action/k8s_log.py create mode 120000 plugins/action/k8s_scale.py create mode 120000 plugins/action/k8s_service.py diff --git a/plugins/action/k8s.py b/plugins/action/k8s.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/k8s.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/k8s_auth.py b/plugins/action/k8s_auth.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/k8s_auth.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/k8s_exec.py b/plugins/action/k8s_exec.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/k8s_exec.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/k8s_info.py b/plugins/action/k8s_info.py new file mode 100644 index 00000000..2b9b84ad --- /dev/null +++ b/plugins/action/k8s_info.py @@ -0,0 +1,82 @@ +# Copyright (c) 2012-2014, Michael DeHaan +# Copyright (c) 2017, Toshio Kuratomi +# Copyright (c) 2020, Ansible Project +# 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 + +import copy +import traceback + +from ansible.module_utils._text import to_text +from ansible.plugins.action import ActionBase +from ansible.errors import AnsibleError + + +class ActionModule(ActionBase): + + TRANSFERS_FILES = True + + def _ensure_invocation(self, result): + # NOTE: adding invocation arguments here needs to be kept in sync with + # any no_log specified in the argument_spec in the module. + if 'invocation' not in result: + if self._play_context.no_log: + result['invocation'] = "CENSORED: no_log is set" + else: + result['invocation'] = self._task.args.copy() + result['invocation']['module_args'] = self._task.args.copy() + + return result + + def run(self, tmp=None, task_vars=None): + ''' handler for k8s options ''' + if task_vars is None: + task_vars = dict() + + result = super(ActionModule, self).run(tmp, task_vars) + del tmp # tmp no longer has any effect + + new_module_args = copy.deepcopy(self._task.args) + kubeconfig = self._task.args.get('kubeconfig', None) + # find the file in the expected search path + if kubeconfig: + try: + # find in expected paths + kubeconfig = self._find_needle('files', kubeconfig) + except AnsibleError as e: + result['failed'] = True + result['msg'] = to_text(e) + result['exception'] = traceback.format_exc() + return result + + if kubeconfig: + # decrypt kubeconfig found + actual_file = self._loader.get_real_file(kubeconfig, decrypt=True) + new_module_args['kubeconfig'] = actual_file + + # find the file in the expected search path + src = self._task.args.get('src', None) + if src: + try: + # find in expected paths + src = self._find_needle('files', src) + except AnsibleError as e: + result['failed'] = True + result['msg'] = to_text(e) + result['exception'] = traceback.format_exc() + return result + + if src: + new_module_args['src'] = src + + # Execute the k8s_* module. + module_return = self._execute_module(module_name=self._task.action, module_args=new_module_args, task_vars=task_vars) + + # Delete tmp path + self._remove_tmp_path(self._connection._shell.tmpdir) + + result.update(module_return) + + return self._ensure_invocation(result) diff --git a/plugins/action/k8s_log.py b/plugins/action/k8s_log.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/k8s_log.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/k8s_scale.py b/plugins/action/k8s_scale.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/k8s_scale.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/k8s_service.py b/plugins/action/k8s_service.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/k8s_service.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file From 16059a8111e233c3fc257980cc5f25859f52ce86 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Wed, 26 Aug 2020 19:48:07 +0530 Subject: [PATCH 70/88] k8s_*: Group argument_spec accroding to usage (#199) Partially fix #36 Signed-off-by: Abhijeet Kasurde --- plugins/doc_fragments/k8s_resource_options.py | 4 +- plugins/module_utils/common.py | 6 ++ plugins/module_utils/raw.py | 4 +- plugins/module_utils/scale.py | 9 ++- plugins/modules/k8s_log.py | 41 ++++---------- plugins/modules/k8s_service.py | 56 ++----------------- tests/sanity/ignore-2.10.txt | 1 + tests/sanity/ignore-2.11.txt | 1 + 8 files changed, 34 insertions(+), 88 deletions(-) diff --git a/plugins/doc_fragments/k8s_resource_options.py b/plugins/doc_fragments/k8s_resource_options.py index 0742eed4..b5721453 100644 --- a/plugins/doc_fragments/k8s_resource_options.py +++ b/plugins/doc_fragments/k8s_resource_options.py @@ -15,8 +15,8 @@ class ModuleDocFragment(object): options: resource_definition: description: - - "Provide a valid YAML definition (either as a string, list, or dict) for an object when creating or updating. NOTE: I(kind), I(api_version), I(name), - and I(namespace) will be overwritten by corresponding values found in the provided I(resource_definition)." + - Provide a valid YAML definition (either as a string, list, or dict) for an object when creating or updating. + - "NOTE: I(kind), I(api_version), I(name), and I(namespace) will be overwritten by corresponding values found in the provided I(resource_definition)." aliases: - definition - inline diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index a94664f6..71e3e28a 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -83,6 +83,9 @@ COMMON_ARG_SPEC = { 'type': 'bool', 'default': False, }, +} + +RESOURCE_ARG_SPEC = { 'resource_definition': { 'type': list_dict_str, 'aliases': ['definition', 'inline'] @@ -90,6 +93,9 @@ COMMON_ARG_SPEC = { 'src': { 'type': 'path', }, +} + +NAME_ARG_SPEC = { 'kind': {}, 'name': {}, 'namespace': {}, diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index bae8f6ea..b694235a 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -25,7 +25,7 @@ import sys import traceback from ansible.module_utils.basic import missing_required_lib -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC +from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC from ansible.module_utils.six import string_types from ansible.module_utils._text import to_native from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule @@ -78,6 +78,8 @@ class KubernetesRawModule(KubernetesAnsibleModule): @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['merge_type'] = dict(type='list', elements='str', choices=['json', 'merge', 'strategic-merge']) argument_spec['wait'] = dict(type='bool', default=False) diff --git a/plugins/module_utils/scale.py b/plugins/module_utils/scale.py index 27f1abe0..27e1f067 100644 --- a/plugins/module_utils/scale.py +++ b/plugins/module_utils/scale.py @@ -21,7 +21,7 @@ __metaclass__ = type import copy -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC +from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule from ansible.module_utils.six import string_types @@ -142,11 +142,10 @@ class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): @property def argspec(self): - args = copy.deepcopy(COMMON_ARG_SPEC) - args.pop('state') - args.pop('force') + args = copy.deepcopy(SCALE_ARG_SPEC) + args.update(RESOURCE_ARG_SPEC) + args.update(NAME_ARG_SPEC) args.update(AUTH_ARG_SPEC) - args.update(SCALE_ARG_SPEC) return args def scale(self, resource, existing_object, replicas, wait, wait_time): diff --git a/plugins/modules/k8s_log.py b/plugins/modules/k8s_log.py index bdf2037a..a30348b2 100644 --- a/plugins/modules/k8s_log.py +++ b/plugins/modules/k8s_log.py @@ -26,40 +26,25 @@ description: - Analogous to `kubectl logs` or `oc logs` extends_documentation_fragment: - community.kubernetes.k8s_auth_options + - community.kubernetes.k8s_name_options options: - api_version: - description: - - Use to specify the API version. in conjunction with I(kind), I(name), and I(namespace) to identify a - specific object. - - If using I(label_selector), cannot be overridden - default: v1 - aliases: - - api - - version - type: str kind: description: - - Use to specify an object model. Use in conjunction with I(api_version), I(name), and I(namespace) to identify a - specific object. - - If using I(label_selector), cannot be overridden - required: no + - Use to specify an object model. + - Use in conjunction with I(api_version), I(name), and I(namespace) to identify a specific object. + - If using I(label_selector), cannot be overridden. + type: str default: Pod - type: str - namespace: - description: - - Use to specify an object namespace. Use in conjunction with I(api_version), I(kind), and I(name) - to identify a specific object. - type: str name: description: - - Use to specify an object name. Use in conjunction with I(api_version), I(kind) and I(namespace) to identify a - specific object. - - Only one of I(name) or I(label_selector) may be provided + - Use to specify an object name. + - Use in conjunction with I(api_version), I(kind) and I(namespace) to identify a specific object. + - Only one of I(name) or I(label_selector) may be provided. type: str label_selectors: description: - List of label selectors to use to filter results - - Only one of I(name) or I(label_selector) may be provided + - Only one of I(name) or I(label_selector) may be provided. type: list elements: str container: @@ -129,7 +114,7 @@ import copy from ansible.module_utils.six import PY2 from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC +from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, NAME_ARG_SPEC class KubernetesLogModule(KubernetesAnsibleModule): @@ -142,12 +127,10 @@ class KubernetesLogModule(KubernetesAnsibleModule): @property def argspec(self): args = copy.deepcopy(AUTH_ARG_SPEC) + args.update(NAME_ARG_SPEC) args.update( dict( - kind=dict(default='Pod'), - api_version=dict(default='v1', aliases=['api', 'version']), - name=dict(), - namespace=dict(), + kind=dict(type='str', default='Pod'), container=dict(), label_selectors=dict(type='list', elements='str', default=[]), ) diff --git a/plugins/modules/k8s_service.py b/plugins/modules/k8s_service.py index 6df0ab5e..932825f7 100644 --- a/plugins/modules/k8s_service.py +++ b/plugins/modules/k8s_service.py @@ -22,43 +22,10 @@ description: extends_documentation_fragment: - community.kubernetes.k8s_auth_options + - community.kubernetes.k8s_resource_options + - community.kubernetes.k8s_state_options options: - resource_definition: - description: - - A partial YAML definition of the Service object being created/updated. Here you can define Kubernetes - Service Resource parameters not covered by this module's parameters. - - "NOTE: I(resource_definition) has lower priority than module parameters. If you try to define e.g. - I(metadata.namespace) here, that value will be ignored and I(metadata) used instead." - aliases: - - definition - - inline - type: dict - src: - description: - - "Provide a path to a file containing a valid YAML definition of an object dated. Mutually - exclusive with I(resource_definition). NOTE: I(kind), I(api_version), I(resource_name), and I(namespace) - will be overwritten by corresponding values found in the configuration read in from the I(src) file." - - Reads from the local file system. To read from the Ansible controller's file system, use the file lookup - plugin or template lookup plugin, combined with the from_yaml filter, and pass the result to - I(resource_definition). See Examples below. - type: path - 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 - module options and I(resource_definition). - default: present - choices: - - present - - absent - type: str - force: - description: - - If set to C(True), and I(state) is C(present), an existing object will be replaced. - default: false - type: bool merge_type: description: - Whether to override the default patch merge approach with a specific type. By default, the strategic @@ -181,7 +148,7 @@ import traceback from collections import defaultdict -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC +from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC, RESOURCE_ARG_SPEC from ansible_collections.community.kubernetes.plugins.module_utils.raw import KubernetesRawModule @@ -190,25 +157,10 @@ SERVICE_ARG_SPEC = { 'type': 'bool', 'default': False, }, - 'state': { - 'default': 'present', - 'choices': ['present', 'absent'], - }, - 'force': { - 'type': 'bool', - 'default': False, - }, - 'resource_definition': { - 'type': 'dict', - 'aliases': ['definition', 'inline'] - }, 'name': {'required': True}, 'namespace': {'required': True}, 'merge_type': {'type': 'list', 'elements': 'str', 'choices': ['json', 'merge', 'strategic-merge']}, 'selector': {'type': 'dict'}, - 'src': { - 'type': 'path', - }, 'type': { 'type': 'str', 'choices': [ @@ -240,6 +192,8 @@ class KubernetesService(KubernetesRawModule): def argspec(self): """ argspec property builder """ argument_spec = copy.deepcopy(AUTH_ARG_SPEC) + argument_spec.update(COMMON_ARG_SPEC) + argument_spec.update(RESOURCE_ARG_SPEC) argument_spec.update(SERVICE_ARG_SPEC) return argument_spec diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt index 0fa8c1c3..326af051 100644 --- a/tests/sanity/ignore-2.10.txt +++ b/tests/sanity/ignore-2.10.txt @@ -3,3 +3,4 @@ plugins/modules/k8s.py validate-modules:return-syntax-error plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s_scale.py validate-modules:return-syntax-error plugins/modules/k8s_service.py validate-modules:return-syntax-error +plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index 0fa8c1c3..326af051 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -3,3 +3,4 @@ plugins/modules/k8s.py validate-modules:return-syntax-error plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s_scale.py validate-modules:return-syntax-error plugins/modules/k8s_service.py validate-modules:return-syntax-error +plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc From 3885eb1a84759f02166c8a956e17a006da2c75a8 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Tue, 18 Aug 2020 17:38:58 -0500 Subject: [PATCH 71/88] add Makefile, downstream build script, enable CI for downstream Signed-off-by: Adam Miller --- .github/workflows/ci.yml | 91 ++++++++++++++++ Makefile | 39 +++++++ README.md | 13 ++- utils/downstream.sh | 220 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 359 insertions(+), 4 deletions(-) create mode 100644 Makefile create mode 100755 utils/downstream.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f28eef96..a11c9c59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,3 +108,94 @@ jobs: - name: Run molecule default test scenario run: molecule test working-directory: ./ansible_collections/community/kubernetes + + downstream-sanity: + runs-on: ubuntu-latest + strategy: + matrix: + python_version: ['3.6'] + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/community/kubernetes + + - name: Set up Python ${{ matrix.python_version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python_version }} + + - name: Install ansible base (devel branch) + run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + + - name: Run sanity tests on Python ${{ matrix.python_version }} + run: make downstream-test-sanity + working-directory: ./ansible_collections/community/kubernetes + + downstream-integration: + runs-on: ubuntu-latest + strategy: + matrix: + python_version: ['3.6'] + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/community/kubernetes + + - name: Set up Python ${{ matrix.python_version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python_version }} + + - name: Install ansible base (devel branch) + run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + + - name: Run integration tests on Python ${{ matrix.python_version }} + run: make downstream-test-integration + working-directory: ./ansible_collections/community/kubernetes + + downstream-molecule: + runs-on: ubuntu-latest + strategy: + matrix: + python_version: ['3.7'] + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/community/kubernetes + + - name: Set up KinD cluster + uses: engineerd/setup-kind@v0.4.0 + + - name: Set up Python ${{ matrix.python_version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python_version }} + + - name: Install molecule and openshift dependencies + run: pip install ansible molecule yamllint openshift flake8 + + # The latest release doesn't work with Molecule currently. + # See: https://github.com/ansible-community/molecule/issues/2757 + # - name: Install ansible base, latest release. + # run: | + # pip uninstall -y ansible + # pip install --pre ansible-base + + # The devel branch doesn't work with Molecule currently. + # See: https://github.com/ansible-community/molecule/issues/2757 + # - name: Install ansible base (devel branch) + # run: | + # pip uninstall -y ansible + # pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + + - name: Create default collection path symlink + run: | + mkdir -p /home/runner/.ansible + ln -s /home/runner/work/kubernetes/kubernetes /home/runner/.ansible/collections + + - name: Run molecule default test scenario + run: make downstream-test-molecule + working-directory: ./ansible_collections/community/kubernetes diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..b1bb4b19 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +# Also needs to be updated in galaxy.yml +VERSION = 1.0.0 + +clean: + rm -f community-kubernetes-${VERSION}.tar.gz + rm -rf ansible_collections + +build: clean + ansible-galaxy collection build + +release: build + ansible-galaxy collection publish community-kubernetes-${VERSION}.tar.gz + +install: build + ansible-galaxy collection install -p ansible_collections community-kubernetes-${VERSION}.tar.gz + +test-sanity: + ansible-test sanity -v --docker --color $(TEST_ARGS) + +test-integration: + ansible-test integration --docker -v --color $(TEST_ARGS) + +test-molecule: + ansible-test integration --docker -v --color $(TEST_ARGS) + +downstream-test-sanity: + ./utils/downstream.sh -s + +downstream-test-integration: + ./utils/downstream.sh -i + +downstream-test-molecule: + ./utils/downstream.sh -m + +downstream-build: + ./utils/downstream.sh -b + +downstream-release: + ./utils/downstream.sh -r diff --git a/README.md b/README.md index d72d2f76..1d2f649d 100644 --- a/README.md +++ b/README.md @@ -136,15 +136,15 @@ The `tests` directory contains configuration for running sanity and integration You can run the collection's test suites with the commands: - ansible-test sanity --docker -v --color - ansible-test integration --docker -v --color + make test-sanity + make test-integration ### Testing with `molecule` -There are also integration tests in the `molecule` directory which are meant to be run against a local Kubernetes cluster, e.g. using [KinD](https://kind.sigs.k8s.io) or [Minikube](https://minikube.sigs.k8s.io). To run the tests, set up a local cluster, then run Molecule: +There are also integration tests in the `molecule` directory which are meant to be run against a local Kubernetes cluster, e.g. using [KinD](https://kind.sigs.k8s.io) or [Minikube](https://minikube.sigs.k8s.io). To setup a local cluster using KinD and run Molecule: kind create cluster - molecule test + make test-molecule ## Publishing New Versions @@ -157,6 +157,11 @@ Releases are automatically built and pushed to Ansible Galaxy for any new tag. B 1. Run `antsibull-changelog release`. 1. Commit the changes and create a PR with the changes. Wait for tests to pass, then merge it once they have. 1. Tag the version in Git and push to GitHub. + 1. Run the following commands to build and release the new version on Galaxy: + + ``` + make release + ``` After the version is published, verify it exists on the [Kubernetes Collection Galaxy page](https://galaxy.ansible.com/community/kubernetes). diff --git a/utils/downstream.sh b/utils/downstream.sh new file mode 100755 index 00000000..d13684a1 --- /dev/null +++ b/utils/downstream.sh @@ -0,0 +1,220 @@ +#!/bin/bash -eu + +# Script to dual-home the upstream and downstream Collection in a single repo +# +# This script will build or test a downstream collection, removing any +# upstream components that will not ship in the downstream release +# +# NOTES: +# - All functions are prefixed with f_ so it's obvious where they come +# from when in use throughout the script + +DOWNSTREAM_VERSION="1.0.0" +KEEP_DOWNSTREAM_TMPDIR="${KEEP_DOWNSTREAM_TMPDIR:-''}" + + +f_log_info() +{ + printf "%s:LOG:INFO: %s\n" "${0}" "${1}\n" +} + +f_prep() +{ + f_log_info "${FUNCNAME[0]}" + # Array of excluded files from downstream build (relative path) + _file_exclude=( + ) + + # Files to copy downstream (relative repo root dir path) + _file_manifest=( + CHANGELOG.rst + galaxy.yml + LICENSE + README.md + Makefile + ) + + # Directories to recursively copy downstream (relative repo root dir path) + _dir_manifest=( + changelogs + meta + plugins + tests + ) + + # Temp build dir + _tmp_dir=$(mktemp -d) + _build_dir="${_tmp_dir}/ansible_collections/kubernetes/base" + mkdir -p "${_build_dir}" +} + +f_show_help() +{ + printf "Usage: downstream.sh [OPTION]\n" + printf "\t-s\t\tCreate a temporary downstream release and perform sanity tests.\n" + printf "\t-i\t\tCreate a temporary downstream release and perform integration tests.\n" + printf "\t-m\t\tCreate a temporary downstream release and perform molecule tests.\n" + printf "\t-b\t\tCreate a downstream release and stage for release.\n" + printf "\t-r\t\tCreate a downstream release and publish release.\n" +} + +f_text_sub() +{ + # Switch FQCN and dependent components + sed -i "s/community-kubernetes/kubernetes-base/" "${_build_dir}/Makefile" + sed -i "s/community\/kubernetes/kubernetes\/base/" "${_build_dir}/Makefile" + sed -i "s/^VERSION\:/VERSION: ${DOWNSTREAM_VERSION}/" "${_build_dir}/Makefile" + sed -i "s/community.kubernetes/kubernetes.base/" "${_build_dir}/galaxy.yml" + sed -i "s/name\:.*$/name: base/" "${_build_dir}/galaxy.yml" + sed -i "s/namespace\:.*$/namespace: kubernetes/" "${_build_dir}/galaxy.yml" + sed -i "s/^version\:.*$/version: ${DOWNSTREAM_VERSION}/" "${_build_dir}/galaxy.yml" + find "${_build_dir}" -type f -exec sed -i "s/community\.kubernetes/kubernetes\.base/g" {} \; +} + +f_cleanup() +{ + f_log_info "${FUNCNAME[0]}" + if [[ -n ${KEEP_DOWNSTREAM_TMPDIR} ]]; then + if [[ -d ${_build_dir} ]]; then + rm -fr "${_build_dir}" + fi + fi +} + +# Exit and handle cleanup processes if needed +f_exit() +{ + f_cleanup + exit "$0" +} + +f_create_collection_dir_structure() +{ + f_log_info "${FUNCNAME[0]}" + # Create the Collection + for f_name in "${_file_manifest[@]}"; + do + cp "./${f_name}" "${_build_dir}/${f_name}" + done + for d_name in "${_dir_manifest[@]}"; + do + cp -r "./${d_name}" "${_build_dir}/${d_name}" + done + for exclude_file in "${_file_exclude[@]}"; + do + if [[ -f "${_build_dir}/${exclude_file}" ]]; then + rm -f "${_build_dir}/${exclude_file}" + fi + done +} + +f_copy_collection_to_working_dir() +{ + f_log_info "${FUNCNAME[0]}" + # Copy the Collection build result into original working dir + cp "${_build_dir}"/*.tar.gz ./ +} + +f_common_steps() +{ + f_log_info "${FUNCNAME[0]}" + f_prep + f_create_collection_dir_structure + f_text_sub +} + +# Run the test sanity scanerio +f_test_sanity_option() +{ + f_log_info "${FUNCNAME[0]}" + f_common_steps + pushd "${_build_dir}" || return + f_log_info "SANITY TEST PWD: ${PWD}" + make test-sanity + popd || return + f_cleanup +} + +# Run the test integration +f_test_integration_option() +{ + f_log_info "${FUNCNAME[0]}" + f_common_steps + pushd "${_build_dir}" || return + f_log_info "INTEGRATION TEST WD: ${PWD}" + make test-integration + popd || return + f_cleanup +} + +# Run the molecule tests +f_test_molecule_option() +{ + f_log_info "${FUNCNAME[0]}" + f_common_steps + pushd "${_build_dir}" || return + f_log_info "MOLECULE TEST WD: ${PWD}" + make test-molecule + popd || return + f_cleanup +} + +# Run the release scanerio +f_release_option() +{ + f_log_info "${FUNCNAME[0]}" + f_common_steps + pushd "${_build_dir}" || return + f_log_info "RELEASE WD: ${PWD}" + make release + popd || return + f_cleanup +} + +# Run the build scanerio +f_build_option() +{ + f_log_info "${FUNCNAME[0]}" + f_common_steps + pushd "${_build_dir}" || return + f_log_info "BUILD WD: ${PWD}" + make build + popd || return + f_copy_collection_to_working_dir + f_cleanup +} + +# If no options are passed, display usage and exit +if [[ "${#}" -eq "0" ]]; then + f_show_help + f_exit 0 +fi + +# Handle options +while getopts ":simrb" option +do + case $option in + s) + f_test_sanity_option + ;; + i) + f_test_integration_option + ;; + m) + f_test_molecule_option + ;; + r) + f_release_option + ;; + b) + f_build_option + ;; + *) + printf "ERROR: Unimplemented option chosen.\n" + f_show_help + f_exit 1 + ;; # Default. + esac +done + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 From 5f34d84f676b2cd2b6e0e1cdbf578b47220e69b6 Mon Sep 17 00:00:00 2001 From: Jeff Geerling Date: Wed, 26 Aug 2020 11:19:05 -0500 Subject: [PATCH 72/88] PR #196 follow-up: Adjust stale bot exemptLabels. --- .github/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/stale.yml b/.github/stale.yml index 4818ef4d..230cf78a 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -16,10 +16,10 @@ onlyLabels: [] # Issues or Pull Requests with these labels will never be considered stale. Set # to `[]` to disable exemptLabels: - - pinned - security - planned - priority/critical + - lifecycle/frozen - verified # Set to true to ignore issues in a project (defaults to false) From f9fc0f7d69ec7223f35250a3c337cbb361a7d347 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 26 Aug 2020 11:33:00 -0500 Subject: [PATCH 73/88] fix README, use Makefile everywhere Signed-off-by: Adam Miller --- .github/workflows/ci.yml | 6 +++--- Makefile | 9 ++++++--- README.md | 5 ----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a11c9c59..370669af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check - name: Run sanity tests on Python ${{ matrix.python_version }} - run: ansible-test sanity --docker -v --color --python ${{ matrix.python_version }} + run: make test-sanity PYTHON_VERSION=${{ matrix.python_version }} working-directory: ./ansible_collections/community/kubernetes integration: @@ -53,7 +53,7 @@ jobs: run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check - name: Run integration tests on Python ${{ matrix.python_version }} - run: ansible-test integration --docker -v --color --retry-on-error --python ${{ matrix.python_version }} --continue-on-error --diff --coverage + run: make test-integration PYTHON_VERSION=${{ matrix.python_version }} working-directory: ./ansible_collections/community/kubernetes - name: Generate coverage report. @@ -106,7 +106,7 @@ jobs: ln -s /home/runner/work/kubernetes/kubernetes /home/runner/.ansible/collections - name: Run molecule default test scenario - run: molecule test + run: make test-molecule working-directory: ./ansible_collections/community/kubernetes downstream-sanity: diff --git a/Makefile b/Makefile index b1bb4b19..9dcd286f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ # Also needs to be updated in galaxy.yml VERSION = 1.0.0 +TEST_ARGS ?= "" +PYTHON_VERSION ?= `python -c 'import platform; print("{0}.{1}".format(platform.python_version_tuple()[0], platform.python_version_tuple()[1]))'` + clean: rm -f community-kubernetes-${VERSION}.tar.gz rm -rf ansible_collections @@ -15,13 +18,13 @@ install: build ansible-galaxy collection install -p ansible_collections community-kubernetes-${VERSION}.tar.gz test-sanity: - ansible-test sanity -v --docker --color $(TEST_ARGS) + ansible-test sanity --docker -v --color --python $(PYTHON_VERSION) $(TEST_ARGS) test-integration: - ansible-test integration --docker -v --color $(TEST_ARGS) + ansible-test integration --docker -v --color --retry-on-error --python $(PYTHON_VERSION) --continue-on-error --diff --coverage $(TEST_ARGS) test-molecule: - ansible-test integration --docker -v --color $(TEST_ARGS) + molecule test downstream-test-sanity: ./utils/downstream.sh -s diff --git a/README.md b/README.md index 1d2f649d..e3d7c6b9 100644 --- a/README.md +++ b/README.md @@ -157,11 +157,6 @@ Releases are automatically built and pushed to Ansible Galaxy for any new tag. B 1. Run `antsibull-changelog release`. 1. Commit the changes and create a PR with the changes. Wait for tests to pass, then merge it once they have. 1. Tag the version in Git and push to GitHub. - 1. Run the following commands to build and release the new version on Galaxy: - - ``` - make release - ``` After the version is published, verify it exists on the [Kubernetes Collection Galaxy page](https://galaxy.ansible.com/community/kubernetes). From b5eba332c9a7051358717fe6a08491591c6caf79 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 26 Aug 2020 11:49:50 -0500 Subject: [PATCH 74/88] fix makefile Signed-off-by: Adam Miller --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9dcd286f..a6f0938c 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ PYTHON_VERSION ?= `python -c 'import platform; print("{0}.{1}".format(platform.p clean: rm -f community-kubernetes-${VERSION}.tar.gz rm -rf ansible_collections + rm -rf tests/output build: clean ansible-galaxy collection build @@ -18,10 +19,10 @@ install: build ansible-galaxy collection install -p ansible_collections community-kubernetes-${VERSION}.tar.gz test-sanity: - ansible-test sanity --docker -v --color --python $(PYTHON_VERSION) $(TEST_ARGS) + ansible-test sanity --docker -v --color --python $(PYTHON_VERSION) $(?TEST_ARGS) test-integration: - ansible-test integration --docker -v --color --retry-on-error --python $(PYTHON_VERSION) --continue-on-error --diff --coverage $(TEST_ARGS) + ansible-test integration --docker -v --color --retry-on-error --python $(PYTHON_VERSION) --continue-on-error --diff --coverage $(?TEST_ARGS) test-molecule: molecule test From f2053480912d5920d531c24c5ead3ceeeeb4fb20 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 26 Aug 2020 12:55:56 -0500 Subject: [PATCH 75/88] fix downstream molecule tests Signed-off-by: Adam Miller --- utils/downstream.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/downstream.sh b/utils/downstream.sh index d13684a1..14348713 100755 --- a/utils/downstream.sh +++ b/utils/downstream.sh @@ -32,6 +32,7 @@ f_prep() LICENSE README.md Makefile + .yamllint ) # Directories to recursively copy downstream (relative repo root dir path) @@ -40,6 +41,7 @@ f_prep() meta plugins tests + molecule ) # Temp build dir From ec74038a1e41e764a157738f53f05217b7a4ebc0 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 26 Aug 2020 13:07:14 -0500 Subject: [PATCH 76/88] need flake8 setup.cfg for downstream tests also Signed-off-by: Adam Miller --- utils/downstream.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/downstream.sh b/utils/downstream.sh index 14348713..96fda78f 100755 --- a/utils/downstream.sh +++ b/utils/downstream.sh @@ -32,6 +32,7 @@ f_prep() LICENSE README.md Makefile + setup.cfg .yamllint ) From 1c5a8fd49f8a55d1fbed889194719f4726325d61 Mon Sep 17 00:00:00 2001 From: Fabian von Feilitzsch Date: Wed, 26 Aug 2020 14:48:40 -0400 Subject: [PATCH 77/88] Set the connection plugin and transport separately, add tests --- molecule/default/converge.yml | 84 ++++++++++++++++++++++++++++++++++ molecule/default/molecule.yml | 5 ++ molecule/default/vars/main.yml | 3 ++ plugins/inventory/k8s.py | 3 +- 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 68dd56b3..f1aa68fc 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -30,3 +30,87 @@ roles: - helm + + post_tasks: + - name: Ensure namespace exists + k8s: + api_version: v1 + kind: Namespace + name: inventory + + - name: Add a deployment + k8s: + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: inventory + namespace: inventory + spec: + replicas: 1 + selector: + matchLabels: + app: "{{ k8s_pod_name }}" + template: "{{ k8s_pod_template }}" + wait: yes + wait_timeout: 120 + vars: + k8s_pod_name: inventory + k8s_pod_image: python + k8s_pod_command: + - python + - '-m' + - http.server + k8s_pod_env: + - name: TEST + value: test + + - meta: refresh_inventory + +- name: Verify inventory and connection plugins + hosts: namespace_inventory_pods + gather_facts: no + + vars: + file_content: | + Hello world + + tasks: + - name: End play if host not running (TODO should we not add these to the inventory?) + meta: end_host + when: pod_phase != "Running" + + - debug: var=hostvars + - setup: + + - debug: var=ansible_facts + + - name: Assert the TEST environment variable was retrieved + assert: + that: ansible_facts.env.TEST == 'test' + + - name: Copy a file into the host + copy: + content: '{{ file_content }}' + dest: /tmp/test_file + + - name: Retrieve the file from the host + slurp: + src: /tmp/test_file + register: slurped_file + + - name: Assert the file content matches expectations + assert: + that: (slurped_file.content|b64decode) == file_content + +- name: Delete inventory namespace + hosts: localhost + connection: local + gather_facts: no + tasks: + - name: Remove inventory namespace + k8s: + api_version: v1 + kind: Namespace + name: inventory + state: absent diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 37cb0028..693cd351 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -15,8 +15,13 @@ platforms: provisioner: name: ansible log: true + config_options: + inventory: + enable_plugins: community.kubernetes.k8s lint: {} inventory: + hosts: + plugin: community.kubernetes.k8s host_vars: localhost: ansible_python_interpreter: '{{ ansible_playbook_python }}' diff --git a/molecule/default/vars/main.yml b/molecule/default/vars/main.yml index 069a0139..a478de97 100644 --- a/molecule/default/vars/main.yml +++ b/molecule/default/vars/main.yml @@ -17,6 +17,7 @@ k8s_pod_spec: - /bin/true resources: "{{ k8s_pod_resources }}" ports: "{{ k8s_pod_ports }}" + env: "{{ k8s_pod_env }}" k8s_pod_service_account: default @@ -30,6 +31,8 @@ k8s_pod_command: [] k8s_pod_ports: [] +k8s_pod_env: [] + k8s_pod_template: metadata: "{{ k8s_pod_metadata }}" spec: "{{ k8s_pod_spec }}" diff --git a/plugins/inventory/k8s.py b/plugins/inventory/k8s.py index d2bbc3fb..4c9bab82 100644 --- a/plugins/inventory/k8s.py +++ b/plugins/inventory/k8s.py @@ -143,6 +143,7 @@ class K8sInventoryException(Exception): class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, K8sAnsibleMixin): NAME = 'community.kubernetes.k8s' + connection_plugin = 'kubectl' transport = 'kubectl' def parse(self, inventory, loader, path, cache=True): @@ -276,7 +277,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable, K8sAnsibleM self.inventory.set_variable(container_name, 'container_state', 'Waiting') self.inventory.set_variable(container_name, 'container_ready', container.ready) self.inventory.set_variable(container_name, 'ansible_remote_tmp', '/tmp/') - self.inventory.set_variable(container_name, 'ansible_connection', self.transport) + self.inventory.set_variable(container_name, 'ansible_connection', self.connection_plugin) self.inventory.set_variable(container_name, 'ansible_{0}_pod'.format(self.transport), pod_name) self.inventory.set_variable(container_name, 'ansible_{0}_container'.format(self.transport), From 8c7ea120245911e507b277ec8312ad40451abda2 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 26 Aug 2020 15:07:21 -0500 Subject: [PATCH 78/88] only test downstream against Ansible 2.9.x Signed-off-by: Adam Miller --- .github/workflows/ci.yml | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 370669af..3971bc4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,7 +109,7 @@ jobs: run: make test-molecule working-directory: ./ansible_collections/community/kubernetes - downstream-sanity: + downstream-sanity-2.9: runs-on: ubuntu-latest strategy: matrix: @@ -126,13 +126,13 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install ansible base (devel branch) - run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + run: pip install "ansible>=2.9.0,<2.10.0" - name: Run sanity tests on Python ${{ matrix.python_version }} run: make downstream-test-sanity working-directory: ./ansible_collections/community/kubernetes - downstream-integration: + downstream-integration-2.9: runs-on: ubuntu-latest strategy: matrix: @@ -149,13 +149,13 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install ansible base (devel branch) - run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + run: pip install "ansible>=2.9.0,<2.10.0" - name: Run integration tests on Python ${{ matrix.python_version }} run: make downstream-test-integration working-directory: ./ansible_collections/community/kubernetes - downstream-molecule: + downstream-molecule-2.9: runs-on: ubuntu-latest strategy: matrix: @@ -175,21 +175,7 @@ jobs: python-version: ${{ matrix.python_version }} - name: Install molecule and openshift dependencies - run: pip install ansible molecule yamllint openshift flake8 - - # The latest release doesn't work with Molecule currently. - # See: https://github.com/ansible-community/molecule/issues/2757 - # - name: Install ansible base, latest release. - # run: | - # pip uninstall -y ansible - # pip install --pre ansible-base - - # The devel branch doesn't work with Molecule currently. - # See: https://github.com/ansible-community/molecule/issues/2757 - # - name: Install ansible base (devel branch) - # run: | - # pip uninstall -y ansible - # pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check + run: pip install "ansible>=2.9.0,<2.10.0" molecule yamllint openshift flake8 - name: Create default collection path symlink run: | From 827807392d6bb4bebfdd4d9ca5417dd6e92bec9d Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Thu, 27 Aug 2020 22:08:01 -0500 Subject: [PATCH 79/88] fix CI tests, helm picked up the same argspec addition as some k8s modules Signed-off-by: Adam Miller --- tests/sanity/ignore-2.10.txt | 2 ++ tests/sanity/ignore-2.11.txt | 2 ++ tests/sanity/ignore-2.9.txt | 3 +++ 3 files changed, 7 insertions(+) diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt index 326af051..3f72c0e6 100644 --- a/tests/sanity/ignore-2.10.txt +++ b/tests/sanity/ignore-2.10.txt @@ -1,3 +1,5 @@ +plugins/modules/helm.py validate-modules:parameter-type-not-in-doc +plugins/modules/helm_info.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s.py validate-modules:return-syntax-error plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index 326af051..3f72c0e6 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -1,3 +1,5 @@ +plugins/modules/helm.py validate-modules:parameter-type-not-in-doc +plugins/modules/helm_info.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s.py validate-modules:return-syntax-error plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt index bbd327f7..9739b5d8 100644 --- a/tests/sanity/ignore-2.9.txt +++ b/tests/sanity/ignore-2.9.txt @@ -1,2 +1,5 @@ +plugins/modules/helm.py validate-modules:parameter-type-not-in-doc +plugins/modules/helm_info.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc +plugins/modules/k8s_service.py validate-modules:parameter-type-not-in-doc From d17858c6dd0076482f3311f1fe2e1baacb5637d2 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Fri, 28 Aug 2020 13:57:07 -0500 Subject: [PATCH 80/88] fix downstream ci names Signed-off-by: Adam Miller --- .github/workflows/ci.yml | 6 +++--- tests/sanity/ignore-2.11.txt | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3971bc4f..5eb9b67f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,7 +109,7 @@ jobs: run: make test-molecule working-directory: ./ansible_collections/community/kubernetes - downstream-sanity-2.9: + downstream-sanity-29: runs-on: ubuntu-latest strategy: matrix: @@ -132,7 +132,7 @@ jobs: run: make downstream-test-sanity working-directory: ./ansible_collections/community/kubernetes - downstream-integration-2.9: + downstream-integration-29: runs-on: ubuntu-latest strategy: matrix: @@ -155,7 +155,7 @@ jobs: run: make downstream-test-integration working-directory: ./ansible_collections/community/kubernetes - downstream-molecule-2.9: + downstream-molecule-29: runs-on: ubuntu-latest strategy: matrix: diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index 3f72c0e6..326af051 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -1,5 +1,3 @@ -plugins/modules/helm.py validate-modules:parameter-type-not-in-doc -plugins/modules/helm_info.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc plugins/modules/k8s.py validate-modules:return-syntax-error plugins/modules/k8s_scale.py validate-modules:parameter-type-not-in-doc From 23f9588732a65108ef22289e4e6704fe9fd2acf9 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 31 Aug 2020 09:29:27 +0530 Subject: [PATCH 81/88] kubectl: correct usage in console (#204) kubectl exec is printed twice in the console log. Fixes: #200 Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/200_kubectl_fix.yml | 2 ++ plugins/connection/kubectl.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/200_kubectl_fix.yml diff --git a/changelogs/fragments/200_kubectl_fix.yml b/changelogs/fragments/200_kubectl_fix.yml new file mode 100644 index 00000000..91430dc1 --- /dev/null +++ b/changelogs/fragments/200_kubectl_fix.yml @@ -0,0 +1,2 @@ +minor_changes: +- kubectl plugin - correct console log (https://github.com/ansible-collections/community.kubernetes/issues/200). diff --git a/plugins/connection/kubectl.py b/plugins/connection/kubectl.py index f3015e2e..5c16fe9e 100644 --- a/plugins/connection/kubectl.py +++ b/plugins/connection/kubectl.py @@ -228,7 +228,8 @@ class Connection(ConnectionBase): def _build_exec_cmd(self, cmd): """ Build the local kubectl exec command to run cmd on remote_host """ - local_cmd = censored_local_cmd = [self.transport_cmd] + local_cmd = [self.transport_cmd] + censored_local_cmd = [self.transport_cmd] # Build command options based on doc string doc_yaml = AnsibleLoader(self.documentation).get_single_data() From 60c762bb37482f055ac5c335dc56a3868668ba49 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Sun, 30 Aug 2020 23:28:06 -0500 Subject: [PATCH 82/88] fix downstream collection name kubernetes.base -> kubernetes.core (#213) Signed-off-by: Adam Miller --- utils/downstream.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/downstream.sh b/utils/downstream.sh index 96fda78f..ce7d539a 100755 --- a/utils/downstream.sh +++ b/utils/downstream.sh @@ -47,7 +47,7 @@ f_prep() # Temp build dir _tmp_dir=$(mktemp -d) - _build_dir="${_tmp_dir}/ansible_collections/kubernetes/base" + _build_dir="${_tmp_dir}/ansible_collections/kubernetes/core" mkdir -p "${_build_dir}" } @@ -64,14 +64,14 @@ f_show_help() f_text_sub() { # Switch FQCN and dependent components - sed -i "s/community-kubernetes/kubernetes-base/" "${_build_dir}/Makefile" - sed -i "s/community\/kubernetes/kubernetes\/base/" "${_build_dir}/Makefile" + sed -i "s/community-kubernetes/kubernetes-core/" "${_build_dir}/Makefile" + sed -i "s/community\/kubernetes/kubernetes\/core/" "${_build_dir}/Makefile" sed -i "s/^VERSION\:/VERSION: ${DOWNSTREAM_VERSION}/" "${_build_dir}/Makefile" - sed -i "s/community.kubernetes/kubernetes.base/" "${_build_dir}/galaxy.yml" - sed -i "s/name\:.*$/name: base/" "${_build_dir}/galaxy.yml" + sed -i "s/community.kubernetes/kubernetes.core/" "${_build_dir}/galaxy.yml" + sed -i "s/name\:.*$/name: core/" "${_build_dir}/galaxy.yml" sed -i "s/namespace\:.*$/namespace: kubernetes/" "${_build_dir}/galaxy.yml" sed -i "s/^version\:.*$/version: ${DOWNSTREAM_VERSION}/" "${_build_dir}/galaxy.yml" - find "${_build_dir}" -type f -exec sed -i "s/community\.kubernetes/kubernetes\.base/g" {} \; + find "${_build_dir}" -type f -exec sed -i "s/community\.kubernetes/kubernetes\.core/g" {} \; } f_cleanup() From c49f896fa089c689d1344f8599c461dc982a7a6e Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 7 Sep 2020 12:42:00 +0530 Subject: [PATCH 83/88] helm: Add replace parameter (#214) Fixes: #106 Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/106-helm_replace.yml | 2 + .../default/roles/helm/tasks/tests_chart.yml | 57 +++++++++++++++++++ plugins/modules/helm.py | 35 ++++++++++-- 3 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/106-helm_replace.yml diff --git a/changelogs/fragments/106-helm_replace.yml b/changelogs/fragments/106-helm_replace.yml new file mode 100644 index 00000000..6fd7b654 --- /dev/null +++ b/changelogs/fragments/106-helm_replace.yml @@ -0,0 +1,2 @@ +bugfixes: +- helm - add replace parameter (https://github.com/ansible-collections/community.kubernetes/issues/106). diff --git a/molecule/default/roles/helm/tasks/tests_chart.yml b/molecule/default/roles/helm/tasks/tests_chart.yml index b0341330..26cf19f0 100644 --- a/molecule/default/roles/helm/tasks/tests_chart.yml +++ b/molecule/default/roles/helm/tasks/tests_chart.yml @@ -201,6 +201,63 @@ that: - install is not changed +# Test --replace +- name: Install chart for replace option + helm: + binary_path: "{{ helm_binary }}" + name: test-0001 + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + register: install + +- name: "Assert that {{ chart_test }} chart is installed from {{ source }}" + assert: + that: + - install is changed + +- name: Remove {{ chart_test }} with --purge + helm: + binary_path: "{{ helm_binary }}" + state: absent + name: test-0001 + purge: False + namespace: "{{ helm_namespace }}" + register: install + +- name: Check if chart is removed + assert: + that: + - install is changed + +- name: Install chart again with same name test-0001 + helm: + binary_path: "{{ helm_binary }}" + name: test-0001 + chart_ref: "{{ chart_source }}" + chart_version: "{{ chart_source_version | default(omit) }}" + namespace: "{{ helm_namespace }}" + replace: True + register: install + +- name: "Assert that {{ chart_test }} chart is installed from {{ source }}" + assert: + that: + - install is changed + +- name: Remove {{ chart_test }} (cleanup) + helm: + binary_path: "{{ helm_binary }}" + state: absent + name: test-0001 + namespace: "{{ helm_namespace }}" + register: install + +- name: Check if chart is removed + assert: + that: + - install is changed + - name: Remove helm namespace k8s: api_version: v1 diff --git a/plugins/modules/helm.py b/plugins/modules/helm.py index 9045dc05..c6870efa 100644 --- a/plugins/modules/helm.py +++ b/plugins/modules/helm.py @@ -115,6 +115,13 @@ options: type: bool default: False version_added: "0.11.1" + replace: + description: + - Reuse the given name, only if that name is a deleted release which remains in the history. + - This is unsafe in production environment. + type: bool + default: False + version_added: "1.11.0" extends_documentation_fragment: - community.kubernetes.helm_common_options ''' @@ -320,14 +327,20 @@ def fetch_chart_info(command, chart_ref): return yaml.safe_load(out) -def deploy(command, release_name, release_values, chart_name, wait, wait_timeout, disable_hook, force, atomic=False, create_namespace=False): +def deploy(command, release_name, release_values, chart_name, wait, + wait_timeout, disable_hook, force, atomic=False, create_namespace=False, + replace=False): """ Install/upgrade/rollback release chart """ - deploy_command = command + " upgrade -i" # install/upgrade + if replace: + # '--replace' is not supported by 'upgrade -i' + deploy_command = command + " install" + else: + deploy_command = command + " upgrade -i" # install/upgrade - # Always reset values to keep release_values equal to values released - deploy_command += " --reset-values" + # Always reset values to keep release_values equal to values released + deploy_command += " --reset-values" if wait: deploy_command += " --wait" @@ -340,6 +353,9 @@ def deploy(command, release_name, release_values, chart_name, wait, wait_timeout if force: deploy_command += " --force" + if replace: + deploy_command += " --replace" + if disable_hook: deploy_command += " --no-hooks" @@ -399,6 +415,7 @@ def main(): wait_timeout=dict(type='str'), atomic=dict(type='bool', default=False), create_namespace=dict(type='bool', default=False), + replace=dict(type='bool', default=False), ), required_if=[ ('release_state', 'present', ['release_name', 'chart_ref']), @@ -432,6 +449,7 @@ def main(): wait_timeout = module.params.get('wait_timeout') atomic = module.params.get('atomic') create_namespace = module.params.get('create_namespace') + replace = module.params.get('replace') if bin_path is not None: helm_cmd_common = bin_path @@ -455,6 +473,9 @@ def main(): # keep helm_cmd_common for get_release_status in module_exit_json helm_cmd = helm_cmd_common if release_state == "absent" and release_status is not None: + if replace: + module.fail_json(msg="replace is not applicable when state is absent") + helm_cmd = delete(helm_cmd, release_name, purge, disable_hook) changed = True elif release_state == "present": @@ -470,13 +491,15 @@ def main(): if release_status is None: # Not installed helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, - disable_hook, False, atomic=atomic, create_namespace=create_namespace) + disable_hook, False, atomic=atomic, create_namespace=create_namespace, + replace=replace) changed = True elif force or release_values != release_status['values'] \ or (chart_info['name'] + '-' + chart_info['version']) != release_status["chart"]: helm_cmd = deploy(helm_cmd, release_name, release_values, chart_ref, wait, wait_timeout, - disable_hook, force, atomic=atomic, create_namespace=create_namespace) + disable_hook, force, atomic=atomic, create_namespace=create_namespace, + replace=replace) changed = True if module.check_mode: From ffb7032dc262e9996ea575c0edcdf58731bcefb6 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 7 Sep 2020 19:03:28 +0530 Subject: [PATCH 84/88] handle exception raised due to DynamicClient Signed-off-by: Abhijeet Kasurde --- plugins/module_utils/common.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 71e3e28a..9cfb5c49 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -221,7 +221,10 @@ class K8sAnsibleMixin(object): setattr(configuration, key, value) kubernetes.client.Configuration.set_default(configuration) - return DynamicClient(kubernetes.client.ApiClient(configuration)) + try: + return DynamicClient(kubernetes.client.ApiClient(configuration)) + except Exception as err: + self.fail(msg='Failed to get client due to %s' % to_native(err)) def find_resource(self, kind, api_version, fail=False): for attribute in ['kind', 'name', 'singular_name']: From 527859c9cd07838b10373e772e00f6fa010e94e4 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Tue, 8 Sep 2020 20:37:16 +0530 Subject: [PATCH 85/88] Refactor module_utils (#223) Moved a bunch of common things to module_utils. --- plugins/module_utils/common.py | 55 +++++++++++++++++++++------------- plugins/module_utils/raw.py | 32 +------------------- plugins/module_utils/scale.py | 28 +---------------- plugins/modules/k8s_log.py | 17 ++++++----- 4 files changed, 46 insertions(+), 86 deletions(-) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 71e3e28a..910446ab 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -18,7 +18,6 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -import copy from datetime import datetime import time import os @@ -63,11 +62,7 @@ except ImportError: def list_dict_str(value): - if isinstance(value, list): - return value - elif isinstance(value, dict): - return value - elif isinstance(value, string_types): + if isinstance(value, (list, dict, string_types)): return value raise TypeError @@ -160,20 +155,6 @@ AUTH_ARG_MAP = { class K8sAnsibleMixin(object): - _argspec_cache = None - - @property - def argspec(self): - """ - Introspect the model properties, and return an Ansible module arg_spec dict. - :return: dict - """ - if self._argspec_cache: - return self._argspec_cache - argument_spec = copy.deepcopy(COMMON_ARG_SPEC) - argument_spec.update(copy.deepcopy(AUTH_ARG_SPEC)) - self._argspec_cache = argument_spec - return self._argspec_cache def get_api_client(self, **auth_params): auth_params = auth_params or getattr(self, 'params', {}) @@ -395,3 +376,37 @@ class KubernetesAnsibleModule(AnsibleModule, K8sAnsibleMixin): else: predicate = _resource_absent return self._wait_for(resource, definition['metadata']['name'], definition['metadata'].get('namespace'), predicate, sleep, timeout, state) + + def set_resource_definitions(self): + resource_definition = self.params.get('resource_definition') + + self.resource_definitions = [] + + if resource_definition: + if isinstance(resource_definition, string_types): + try: + self.resource_definitions = yaml.safe_load_all(resource_definition) + except (IOError, yaml.YAMLError) as exc: + self.fail(msg="Error loading resource_definition: {0}".format(exc)) + elif isinstance(resource_definition, list): + self.resource_definitions = resource_definition + else: + self.resource_definitions = [resource_definition] + + src = self.params.get('src') + if src: + self.resource_definitions = self.load_resource_definitions(src) + try: + self.resource_definitions = [item for item in self.resource_definitions if item] + except AttributeError: + pass + + if not resource_definition and not src: + implicit_definition = dict( + kind=self.kind, + apiVersion=self.api_version, + metadata=dict(name=self.name) + ) + if self.namespace: + implicit_definition['metadata']['namespace'] = self.namespace + self.resource_definitions = [implicit_definition] diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index b694235a..dc8e8aa0 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -26,14 +26,12 @@ import traceback from ansible.module_utils.basic import missing_required_lib from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC -from ansible.module_utils.six import string_types from ansible.module_utils._text import to_native from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule from ansible.module_utils.common.dict_transformations import dict_merge try: - import yaml from openshift.dynamic.exceptions import DynamicApiError, NotFoundError, ConflictError, ForbiddenError, KubernetesValidateMissing import urllib3 except ImportError: @@ -108,7 +106,6 @@ class KubernetesRawModule(KubernetesAnsibleModule): self.api_version = self.params.get('api_version') self.name = self.params.get('name') self.namespace = self.params.get('namespace') - resource_definition = self.params.get('resource_definition') validate = self.params.get('validate') if validate: if LooseVersion(self.openshift_version) < LooseVersion("0.8.0"): @@ -125,34 +122,7 @@ class KubernetesRawModule(KubernetesAnsibleModule): if self.apply: if not HAS_K8S_APPLY: self.fail_json(msg=missing_required_lib("openshift >= 0.9.2", reason="for apply")) - - if resource_definition: - if isinstance(resource_definition, string_types): - try: - self.resource_definitions = yaml.safe_load_all(resource_definition) - except (IOError, yaml.YAMLError) as exc: - self.fail(msg="Error loading resource_definition: {0}".format(exc)) - elif isinstance(resource_definition, list): - self.resource_definitions = resource_definition - else: - self.resource_definitions = [resource_definition] - src = self.params.get('src') - if src: - self.resource_definitions = self.load_resource_definitions(src) - try: - self.resource_definitions = [item for item in self.resource_definitions if item] - except AttributeError: - pass - - if not resource_definition and not src: - implicit_definition = dict( - kind=self.kind, - apiVersion=self.api_version, - metadata=dict(name=self.name) - ) - if self.namespace: - implicit_definition['metadata']['namespace'] = self.namespace - self.resource_definitions = [implicit_definition] + self.set_resource_definitions() def flatten_list_kind(self, list_resource, definitions): flattened = [] diff --git a/plugins/module_utils/scale.py b/plugins/module_utils/scale.py index 27e1f067..b989894d 100644 --- a/plugins/module_utils/scale.py +++ b/plugins/module_utils/scale.py @@ -23,10 +23,8 @@ import copy from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule -from ansible.module_utils.six import string_types try: - import yaml from openshift.dynamic.exceptions import NotFoundError except ImportError: pass @@ -59,31 +57,7 @@ class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): self.api_version = self.params.get('api_version') self.name = self.params.get('name') self.namespace = self.params.get('namespace') - resource_definition = self.params.get('resource_definition') - - if resource_definition: - if isinstance(resource_definition, string_types): - try: - self.resource_definitions = yaml.safe_load_all(resource_definition) - except (IOError, yaml.YAMLError) as exc: - self.fail(msg="Error loading resource_definition: {0}".format(exc)) - elif isinstance(resource_definition, list): - self.resource_definitions = resource_definition - else: - self.resource_definitions = [resource_definition] - src = self.params.get('src') - if src: - self.resource_definitions = self.load_resource_definitions(src) - - if not resource_definition and not src: - implicit_definition = dict( - kind=self.kind, - apiVersion=self.api_version, - metadata=dict(name=self.name) - ) - if self.namespace: - implicit_definition['metadata']['namespace'] = self.namespace - self.resource_definitions = [implicit_definition] + self.set_resource_definitions() def execute_module(self): definition = self.resource_definitions[0] diff --git a/plugins/modules/k8s_log.py b/plugins/modules/k8s_log.py index a30348b2..6470d066 100644 --- a/plugins/modules/k8s_log.py +++ b/plugins/modules/k8s_log.py @@ -32,19 +32,19 @@ options: description: - Use to specify an object model. - Use in conjunction with I(api_version), I(name), and I(namespace) to identify a specific object. - - If using I(label_selector), cannot be overridden. + - If using I(label_selectors), cannot be overridden. type: str default: Pod name: description: - Use to specify an object name. - Use in conjunction with I(api_version), I(kind) and I(namespace) to identify a specific object. - - Only one of I(name) or I(label_selector) may be provided. + - Only one of I(name) or I(label_selectors) may be provided. type: str label_selectors: description: - List of label selectors to use to filter results - - Only one of I(name) or I(label_selector) may be provided. + - Only one of I(name) or I(label_selectors) may be provided. type: list elements: str container: @@ -139,6 +139,7 @@ class KubernetesLogModule(KubernetesAnsibleModule): def execute_module(self): name = self.params.get('name') + namespace = self.params.get('namespace') label_selector = ','.join(self.params.get('label_selectors', {})) if name and label_selector: self.fail(msg='Only one of name or label_selectors can be provided') @@ -148,16 +149,16 @@ class KubernetesLogModule(KubernetesAnsibleModule): v1_pods = self.find_resource('Pod', 'v1', fail=True) if 'log' not in resource.subresources: - if not self.params.get('name'): + if not name: self.fail(msg='name must be provided for resources that do not support the log subresource') - instance = resource.get(name=self.params['name'], namespace=self.params.get('namespace')) + instance = resource.get(name=name, namespace=namespace) label_selector = ','.join(self.extract_selectors(instance)) resource = v1_pods if label_selector: - instances = v1_pods.get(namespace=self.params['namespace'], label_selector=label_selector) + instances = v1_pods.get(namespace=namespace, label_selector=label_selector) if not instances.items: - self.fail(msg='No pods in namespace {0} matched selector {1}'.format(self.params['namespace'], label_selector)) + self.fail(msg='No pods in namespace {0} matched selector {1}'.format(namespace, label_selector)) # This matches the behavior of kubectl when logging pods via a selector name = instances.items[0].metadata.name resource = v1_pods @@ -168,7 +169,7 @@ class KubernetesLogModule(KubernetesAnsibleModule): log = serialize_log(resource.log.get( name=name, - namespace=self.params.get('namespace'), + namespace=namespace, serialize=False, **kwargs )) From 0afe40e657a0199be2c20bce9fefb54ce8b94a72 Mon Sep 17 00:00:00 2001 From: Fabian von Feilitzsch Date: Mon, 14 Sep 2020 15:51:08 -0400 Subject: [PATCH 86/88] Do not mark task as changed when diff is irrelevant When the diff contains changes only to the fields `metadata.generation` or `metadata.resourceVersion`, do not mark the task as changed. Instead, emit a warning highlighting that the API itself may not be idempotent, but that there was no meaningful difference between the desired and actual state of the resource. --- plugins/module_utils/common.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 910446ab..40b96a66 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -256,14 +256,30 @@ class K8sAnsibleMixin(object): self.fail(msg="Error loading resource_definition: {0}".format(exc)) return result - @staticmethod - def diff_objects(existing, new): + def diff_objects(self, existing, new): result = dict() diff = recursive_diff(existing, new) - if diff: - result['before'] = diff[0] - result['after'] = diff[1] - return not diff, result + if not diff: + return True, result + + result['before'] = diff[0] + result['after'] = diff[1] + + # If only metadata.generation and metadata.resourceVersion changed, ignore it + ignored_keys = set(['generation', 'resourceVersion']) + + if list(result['after'].keys()) != ['metadata'] or list(result['before'].keys()) != ['metadata']: + return False, result + + if not set(result['after']['metadata'].keys()).issubset(ignored_keys): + return False, result + if not set(result['before']['metadata'].keys()).issubset(ignored_keys): + return False, result + + if hasattr(self, 'warn'): + self.warn('No meaningful diff was generated, but the API may not be idempotent (only metadata.generation or metadata.resourceVersion were changed)') + + return True, result class KubernetesAnsibleModule(AnsibleModule, K8sAnsibleMixin): From f2b1b267a5fa74e05b5d99d90f395873eb590808 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Tue, 15 Sep 2020 13:56:43 +0530 Subject: [PATCH 87/88] helm: Support vaulted kubeconfig Signed-off-by: Abhijeet Kasurde --- plugins/action/helm.py | 1 + plugins/action/helm_info.py | 1 + plugins/action/helm_plugin.py | 1 + plugins/action/helm_plugin_info.py | 1 + plugins/action/helm_repository.py | 1 + plugins/doc_fragments/helm_common_options.py | 2 +- 6 files changed, 6 insertions(+), 1 deletion(-) create mode 120000 plugins/action/helm.py create mode 120000 plugins/action/helm_info.py create mode 120000 plugins/action/helm_plugin.py create mode 120000 plugins/action/helm_plugin_info.py create mode 120000 plugins/action/helm_repository.py diff --git a/plugins/action/helm.py b/plugins/action/helm.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/helm.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/helm_info.py b/plugins/action/helm_info.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/helm_info.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/helm_plugin.py b/plugins/action/helm_plugin.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/helm_plugin.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/helm_plugin_info.py b/plugins/action/helm_plugin_info.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/helm_plugin_info.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/action/helm_repository.py b/plugins/action/helm_repository.py new file mode 120000 index 00000000..667980ed --- /dev/null +++ b/plugins/action/helm_repository.py @@ -0,0 +1 @@ +k8s_info.py \ No newline at end of file diff --git a/plugins/doc_fragments/helm_common_options.py b/plugins/doc_fragments/helm_common_options.py index c2204004..f13bc1e3 100644 --- a/plugins/doc_fragments/helm_common_options.py +++ b/plugins/doc_fragments/helm_common_options.py @@ -30,5 +30,5 @@ options: - Helm option to specify kubeconfig path to use. - If the value is not specified in the task, the value of environment variable C(K8S_AUTH_KUBECONFIG) will be used instead. type: path - aliases: [ kubeconfig_path] + aliases: [ kubeconfig_path ] ''' From 51cadb71509396b7bd00a3b0987bc473dae71785 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Wed, 16 Sep 2020 20:35:05 +0530 Subject: [PATCH 88/88] Replace KubernetesAnsibleModule class with dummy class (#227) * Make an AnsibleMixin parent class for every module * Replace KubernetesAnsibleModule class with dummy class * Modified k8s_log * k8s_exec refactor * k8s_info refactor * k8s_service refactor * k8s_scale refactor * Fix integration tests * Add a warning about the deprecation of KubernetesAnsibleModule * Add a dummy class for backward compatibility Signed-off-by: Abhijeet Kasurde --- plugins/module_utils/common.py | 45 ++++++------- plugins/module_utils/raw.py | 27 +++++--- plugins/module_utils/scale.py | 25 +++++-- plugins/modules/k8s_exec.py | 117 ++++++++++++++++++--------------- plugins/modules/k8s_info.py | 20 ++++-- plugins/modules/k8s_log.py | 22 +++++-- 6 files changed, 154 insertions(+), 102 deletions(-) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 2a8ad206..58bb0855 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -156,6 +156,15 @@ AUTH_ARG_MAP = { class K8sAnsibleMixin(object): + def __init__(self, *args, **kwargs): + if not HAS_K8S_MODULE_HELPER: + self.fail_json(msg=missing_required_lib('openshift'), exception=K8S_IMP_ERR, + error=to_native(k8s_import_exception)) + self.openshift_version = openshift.__version__ + + if not HAS_YAML: + self.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR) + def get_api_client(self, **auth_params): auth_params = auth_params or getattr(self, 'params', {}) auth = {} @@ -284,28 +293,6 @@ class K8sAnsibleMixin(object): return True, result - -class KubernetesAnsibleModule(AnsibleModule, K8sAnsibleMixin): - resource_definition = None - api_version = None - kind = None - - def __init__(self, *args, **kwargs): - - kwargs['argument_spec'] = self.argspec - AnsibleModule.__init__(self, *args, **kwargs) - - if not HAS_K8S_MODULE_HELPER: - self.fail_json(msg=missing_required_lib('openshift'), exception=K8S_IMP_ERR, - error=to_native(k8s_import_exception)) - self.openshift_version = openshift.__version__ - - if not HAS_YAML: - self.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR) - - def execute_module(self): - raise NotImplementedError() - def fail(self, msg=None): self.fail_json(msg=msg) @@ -429,3 +416,17 @@ class KubernetesAnsibleModule(AnsibleModule, K8sAnsibleMixin): if self.namespace: implicit_definition['metadata']['namespace'] = self.namespace self.resource_definitions = [implicit_definition] + + +class KubernetesAnsibleModule(AnsibleModule, K8sAnsibleMixin): + # NOTE: This class KubernetesAnsibleModule is deprecated in favor of + # class K8sAnsibleMixin and will be removed 2.0.0 release. + # Please use K8sAnsibleMixin instead. + + def __init__(self, *args, **kwargs): + kwargs['argument_spec'] = self.argspec + AnsibleModule.__init__(self, *args, **kwargs) + K8sAnsibleMixin.__init__(self, *args, **kwargs) + + self.warn("class KubernetesAnsibleModule is deprecated" + " and will be removed in 2.0.0. Please use K8sAnsibleMixin instead.") diff --git a/plugins/module_utils/raw.py b/plugins/module_utils/raw.py index dc8e8aa0..bbe2b2d1 100644 --- a/plugins/module_utils/raw.py +++ b/plugins/module_utils/raw.py @@ -24,11 +24,11 @@ from distutils.version import LooseVersion import sys import traceback -from ansible.module_utils.basic import missing_required_lib -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC +from ansible.module_utils.basic import missing_required_lib, AnsibleModule from ansible.module_utils._text import to_native -from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule from ansible.module_utils.common.dict_transformations import dict_merge +from ansible_collections.community.kubernetes.plugins.module_utils.common import ( + AUTH_ARG_SPEC, COMMON_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC, K8sAnsibleMixin) try: @@ -55,7 +55,7 @@ except ImportError: HAS_K8S_APPLY = False -class KubernetesRawModule(KubernetesAnsibleModule): +class KubernetesRawModule(K8sAnsibleMixin): @property def validate_spec(self): @@ -98,10 +98,21 @@ class KubernetesRawModule(KubernetesAnsibleModule): ('merge_type', 'apply'), ] - KubernetesAnsibleModule.__init__(self, *args, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True, - **kwargs) + 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 + + super(KubernetesRawModule, self).__init__() + self.kind = k8s_kind or self.params.get('kind') self.api_version = self.params.get('api_version') self.name = self.params.get('name') diff --git a/plugins/module_utils/scale.py b/plugins/module_utils/scale.py index b989894d..55bab010 100644 --- a/plugins/module_utils/scale.py +++ b/plugins/module_utils/scale.py @@ -21,8 +21,9 @@ __metaclass__ = type import copy -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC -from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.community.kubernetes.plugins.module_utils.common import ( + AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, NAME_ARG_SPEC, K8sAnsibleMixin) try: from openshift.dynamic.exceptions import NotFoundError @@ -39,7 +40,7 @@ SCALE_ARG_SPEC = { } -class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): +class KubernetesAnsibleScaleModule(K8sAnsibleMixin): def __init__(self, k8s_kind=None, *args, **kwargs): self.client = None @@ -49,10 +50,20 @@ class KubernetesAnsibleScaleModule(KubernetesAnsibleModule): ('resource_definition', 'src'), ] - KubernetesAnsibleModule.__init__(self, *args, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True, - **kwargs) + module = AnsibleModule( + argument_spec=self.argspec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True, + ) + + self.module = module + self.params = self.module.params + self.check_mode = self.module.check_mode + self.fail_json = self.module.fail_json + self.fail = self.module.fail_json + self.exit_json = self.module.exit_json + super(KubernetesAnsibleScaleModule, self).__init__() + self.kind = k8s_kind or self.params.get('kind') self.api_version = self.params.get('api_version') self.name = self.params.get('name') diff --git a/plugins/modules/k8s_exec.py b/plugins/modules/k8s_exec.py index 4c850764..e540b9b6 100644 --- a/plugins/modules/k8s_exec.py +++ b/plugins/modules/k8s_exec.py @@ -109,18 +109,18 @@ result: import copy import shlex -import traceback try: import yaml - IMP_YAML = True except ImportError: - IMP_YAML_ERR = traceback.format_exc() - IMP_YAML = False + # ImportError are managed by the common module already. + pass -from ansible.module_utils.basic import missing_required_lib -from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_native +from ansible_collections.community.kubernetes.plugins.module_utils.common import ( + K8sAnsibleMixin, AUTH_ARG_SPEC +) try: from kubernetes.client.apis import core_v1_api @@ -130,7 +130,18 @@ except ImportError: pass -class KubernetesExecCommand(KubernetesAnsibleModule): +class KubernetesExecCommand(K8sAnsibleMixin): + + def __init__(self): + module = AnsibleModule( + argument_spec=self.argspec, + supports_check_mode=True, + ) + self.module = module + self.params = self.module.params + self.fail_json = self.module.fail_json + super(KubernetesExecCommand, self).__init__() + @property def argspec(self): spec = copy.deepcopy(AUTH_ARG_SPEC) @@ -140,52 +151,54 @@ class KubernetesExecCommand(KubernetesAnsibleModule): spec['command'] = dict(type='str', required=True) return spec + def execute_module(self): + # Load kubernetes.client.Configuration + self.get_api_client() + api = core_v1_api.CoreV1Api() + + # hack because passing the container as None breaks things + optional_kwargs = {} + if self.params.get('container'): + optional_kwargs['container'] = self.params['container'] + try: + resp = stream( + api.connect_get_namespaced_pod_exec, + self.params["pod"], + self.params["namespace"], + command=shlex.split(self.params["command"]), + stdout=True, + stderr=True, + stdin=False, + tty=False, + _preload_content=False, **optional_kwargs) + except Exception as e: + self.module.fail_json(msg="Failed to execute on pod %s" + " due to : %s" % (self.params.get('pod'), to_native(e))) + stdout, stderr, rc = [], [], 0 + while resp.is_open(): + resp.update(timeout=1) + if resp.peek_stdout(): + stdout.append(resp.read_stdout()) + if resp.peek_stderr(): + stderr.append(resp.read_stderr()) + err = resp.read_channel(3) + err = yaml.safe_load(err) + if err['status'] == 'Success': + rc = 0 + else: + rc = int(err['details']['causes'][0]['message']) + + self.module.exit_json( + # Some command might change environment, but ultimately failing at end + changed=True, + stdout="".join(stdout), + stderr="".join(stderr), + return_code=rc + ) + def main(): - module = KubernetesExecCommand() - - if not IMP_YAML: - module.fail_json(msg=missing_required_lib("yaml"), exception=IMP_YAML_ERR) - - # Load kubernetes.client.Configuration - module.get_api_client() - api = core_v1_api.CoreV1Api() - - # hack because passing the container as None breaks things - optional_kwargs = {} - if module.params.get('container'): - optional_kwargs['container'] = module.params['container'] - resp = stream( - api.connect_get_namespaced_pod_exec, - module.params["pod"], - module.params["namespace"], - command=shlex.split(module.params["command"]), - stdout=True, - stderr=True, - stdin=False, - tty=False, - _preload_content=False, **optional_kwargs) - stdout, stderr, rc = [], [], 0 - while resp.is_open(): - resp.update(timeout=1) - if resp.peek_stdout(): - stdout.append(resp.read_stdout()) - if resp.peek_stderr(): - stderr.append(resp.read_stderr()) - err = resp.read_channel(3) - err = yaml.safe_load(err) - if err['status'] == 'Success': - rc = 0 - else: - rc = int(err['details']['causes'][0]['message']) - - module.exit_json( - # Some command might change environment, but ultimately failing at end - changed=True, - stdout="".join(stdout), - stderr="".join(stderr), - return_code=rc - ) + KubernetesExecCommand().execute_module() if __name__ == '__main__': diff --git a/plugins/modules/k8s_info.py b/plugins/modules/k8s_info.py index 2811f534..219c4eec 100644 --- a/plugins/modules/k8s_info.py +++ b/plugins/modules/k8s_info.py @@ -130,17 +130,25 @@ resources: type: dict ''' - -from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule, AUTH_ARG_SPEC import copy +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.community.kubernetes.plugins.module_utils.common import ( + K8sAnsibleMixin, AUTH_ARG_SPEC) -class KubernetesInfoModule(KubernetesAnsibleModule): + +class KubernetesInfoModule(K8sAnsibleMixin): def __init__(self, *args, **kwargs): - KubernetesAnsibleModule.__init__(self, *args, - supports_check_mode=True, - **kwargs) + module = AnsibleModule( + argument_spec=self.argspec, + supports_check_mode=True, + ) + self.module = module + self.params = self.module.params + self.fail_json = self.module.fail_json + self.exit_json = self.module.exit_json + super(KubernetesInfoModule, self).__init__() def execute_module(self): self.client = self.get_api_client() diff --git a/plugins/modules/k8s_log.py b/plugins/modules/k8s_log.py index 6470d066..e7b75711 100644 --- a/plugins/modules/k8s_log.py +++ b/plugins/modules/k8s_log.py @@ -111,18 +111,26 @@ log_lines: import copy +from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six import PY2 -from ansible_collections.community.kubernetes.plugins.module_utils.common import KubernetesAnsibleModule -from ansible_collections.community.kubernetes.plugins.module_utils.common import AUTH_ARG_SPEC, NAME_ARG_SPEC +from ansible_collections.community.kubernetes.plugins.module_utils.common import ( + K8sAnsibleMixin, AUTH_ARG_SPEC, NAME_ARG_SPEC) -class KubernetesLogModule(KubernetesAnsibleModule): +class KubernetesLogModule(K8sAnsibleMixin): - def __init__(self, *args, **kwargs): - KubernetesAnsibleModule.__init__(self, *args, - supports_check_mode=True, - **kwargs) + def __init__(self): + module = AnsibleModule( + argument_spec=self.argspec, + supports_check_mode=True, + ) + self.module = module + 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 + super(KubernetesLogModule, self).__init__() @property def argspec(self):