From e9c7b513a18e736d8f1443baeab009503e7eac6d Mon Sep 17 00:00:00 2001 From: Fabian von Feilitzsch Date: Mon, 9 Jul 2018 09:33:16 -0400 Subject: [PATCH] [k8s] allow user to pass list of resources in to definition parameter (#42377) * allow user to pass list of resources in to definition parameter * Add new validator for list|dict|string * use string_types instead of string * state/force information is lost after the first item in the list * Add tests * Appease ansibot --- lib/ansible/module_utils/k8s/common.py | 13 ++- lib/ansible/module_utils/k8s/raw.py | 9 +- .../k8s_resource_options.py | 2 +- test/integration/targets/k8s/tasks/main.yml | 106 ++++++++++++++++++ 4 files changed, 125 insertions(+), 5 deletions(-) diff --git a/lib/ansible/module_utils/k8s/common.py b/lib/ansible/module_utils/k8s/common.py index ca08264ce0..58e9b46b79 100644 --- a/lib/ansible/module_utils/k8s/common.py +++ b/lib/ansible/module_utils/k8s/common.py @@ -22,8 +22,8 @@ import os import copy -from ansible.module_utils.six import iteritems from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import iteritems, string_types try: import kubernetes @@ -51,6 +51,16 @@ try: except ImportError: pass + +def list_dict_str(value): + if isinstance(value, list): + return value + elif isinstance(value, dict): + return value + elif isinstance(value, string_types): + return value + raise TypeError + ARG_ATTRIBUTES_BLACKLIST = ('property_path',) COMMON_ARG_SPEC = { @@ -63,6 +73,7 @@ COMMON_ARG_SPEC = { 'default': False, }, 'resource_definition': { + 'type': list_dict_str, 'aliases': ['definition', 'inline'] }, 'src': { diff --git a/lib/ansible/module_utils/k8s/raw.py b/lib/ansible/module_utils/k8s/raw.py index 630096957f..a67dd846d6 100644 --- a/lib/ansible/module_utils/k8s/raw.py +++ b/lib/ansible/module_utils/k8s/raw.py @@ -19,6 +19,7 @@ from __future__ import absolute_import, division, print_function +from ansible.module_utils.six import string_types from ansible.module_utils.k8s.common import KubernetesAnsibleModule @@ -50,11 +51,13 @@ class KubernetesRawModule(KubernetesAnsibleModule): namespace = self.params.pop('namespace') resource_definition = self.params.pop('resource_definition') if resource_definition: - if isinstance(resource_definition, str): + 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.pop('src') @@ -100,8 +103,8 @@ class KubernetesRawModule(KubernetesAnsibleModule): def perform_action(self, resource, definition): result = {'changed': False, 'result': {}} - state = self.params.pop('state', None) - force = self.params.pop('force', False) + state = self.params.get('state', None) + force = self.params.get('force', False) name = definition.get('metadata', {}).get('name') namespace = definition.get('metadata', {}).get('namespace') existing = None diff --git a/lib/ansible/utils/module_docs_fragments/k8s_resource_options.py b/lib/ansible/utils/module_docs_fragments/k8s_resource_options.py index 1466210e1f..833e6dd18f 100644 --- a/lib/ansible/utils/module_docs_fragments/k8s_resource_options.py +++ b/lib/ansible/utils/module_docs_fragments/k8s_resource_options.py @@ -25,7 +25,7 @@ class ModuleDocFragment(object): options: resource_definition: description: - - "Provide a valid YAML definition (either as a string or a dict) for an object when creating or updating. NOTE: I(kind), I(api_version), I(name), + - "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 diff --git a/test/integration/targets/k8s/tasks/main.yml b/test/integration/targets/k8s/tasks/main.yml index 1de8b95d78..648b4fad54 100644 --- a/test/integration/targets/k8s/tasks/main.yml +++ b/test/integration/targets/k8s/tasks/main.yml @@ -2,6 +2,10 @@ pip: name: openshift +# TODO: This is the only way I could get the kubeconfig, I don't know why. Running the lookup outside of debug seems to return an empty string +- debug: msg={{ lookup('env', 'K8S_AUTH_KUBECONFIG') }} + register: kubeconfig + # Kubernetes resources - name: Create a namespace k8s: @@ -9,6 +13,8 @@ kind: namespace register: output +- debug: msg={{ lookup("k8s", kind="Namespace", api_version="v1", resource_name='testing', kubeconfig=kubeconfig.msg) }} + - name: show output debug: var: output @@ -188,3 +194,103 @@ - name: DC creation should be idempotent assert: that: not output.changed + +### Type tests +- name: Create a namespace from a string + k8s: + definition: |+ + --- + kind: Namespace + apiVersion: v1 + metadata: + name: testing1 + +- name: Namespace should exist + assert: + that: '{{ lookup("k8s", kind="Namespace", api_version="v1", resource_name="testing1", kubeconfig=kubeconfig.msg).status.phase == "Active" }}' + +- name: Create resources from a multidocument yaml string + k8s: + definition: |+ + --- + kind: Namespace + apiVersion: v1 + metadata: + name: testing2 + --- + kind: Namespace + apiVersion: v1 + metadata: + name: testing3 + +- name: Resources should exist + assert: + that: lookup("k8s", kind="Namespace", api_version="v1", resource_name=item, kubeconfig=kubeconfig.msg).status.phase == "Active" + loop: + - testing2 + - testing3 + +- name: Delete resources from a multidocument yaml string + k8s: + state: absent + definition: |+ + --- + kind: Namespace + apiVersion: v1 + metadata: + name: testing2 + --- + kind: Namespace + apiVersion: v1 + metadata: + name: testing3 + +- name: Resources should not exist + assert: + that: not ns or ns.status.phase == "Terminating" + loop: + - testing2 + - testing3 + vars: + ns: '{{ lookup("k8s", kind="Namespace", api_version="v1", resource_name=item, kubeconfig=kubeconfig.msg) }}' + +- name: Create resources from a list + k8s: + definition: + - kind: Namespace + apiVersion: v1 + metadata: + name: testing4 + - kind: Namespace + apiVersion: v1 + metadata: + name: testing5 + +- name: Resources should exist + assert: + that: lookup("k8s", kind="Namespace", api_version="v1", resource_name=item, kubeconfig=kubeconfig.msg).status.phase == "Active" + loop: + - testing4 + - testing5 + +- name: Delete resources from a list + k8s: + state: absent + definition: + - kind: Namespace + apiVersion: v1 + metadata: + name: testing4 + - kind: Namespace + apiVersion: v1 + metadata: + name: testing5 + +- name: Resources should not exist + assert: + that: not ns or ns.status.phase == "Terminating" + loop: + - testing4 + - testing5 + vars: + ns: '{{ lookup("k8s", kind="Namespace", api_version="v1", resource_name=item, kubeconfig=kubeconfig.msg) }}'