diff --git a/lib/ansible/module_utils/k8s/raw.py b/lib/ansible/module_utils/k8s/raw.py index c7a8cf1bfcf..22e40f8c1bc 100644 --- a/lib/ansible/module_utils/k8s/raw.py +++ b/lib/ansible/module_utils/k8s/raw.py @@ -130,17 +130,34 @@ class KubernetesRawModule(KubernetesAnsibleModule): } }] + def flatten_list_kind(self, list_resource, definitions): + flattened = [] + parent_api_version = list_resource.group_version if list_resource else None + parent_kind = list_resource.kind[:-4] if list_resource else None + for definition in definitions.get('items', []): + resource = self.find_resource(definition.get('kind', parent_kind), definition.get('apiVersion', parent_api_version), fail=True) + flattened.append((resource, self.set_defaults(resource, definition))) + return flattened + def execute_module(self): changed = False results = [] self.client = self.get_api_client() + + flattened_definitions = [] for definition in self.resource_definitions: kind = definition.get('kind', self.kind) - search_kind = kind - if kind.lower().endswith('list'): - search_kind = kind[:-4] api_version = definition.get('apiVersion', self.api_version) - resource = self.find_resource(search_kind, api_version, fail=True) + if kind.endswith('List'): + resource = self.find_resource(kind, api_version, fail=False) + flattened_definitions.extend(self.flatten_list_kind(resource, definition)) + else: + resource = self.find_resource(kind, api_version, fail=True) + flattened_definitions.append((resource, definition)) + + for (resource, definition) in flattened_definitions: + kind = definition.get('kind', self.kind) + api_version = definition.get('apiVersion', self.api_version) definition = self.set_defaults(resource, definition) self.warnings = [] if self.params['validate'] is not None: @@ -177,12 +194,12 @@ class KubernetesRawModule(KubernetesAnsibleModule): def set_defaults(self, resource, definition): definition['kind'] = resource.kind definition['apiVersion'] = resource.group_version - if not definition.get('metadata'): - definition['metadata'] = {} - if self.name and not definition['metadata'].get('name'): - definition['metadata']['name'] = self.name - if resource.namespaced and self.namespace and not definition['metadata'].get('namespace'): - definition['metadata']['namespace'] = self.namespace + metadata = definition.get('metadata', {}) + if self.name and not metadata.get('name'): + metadata['name'] = self.name + if resource.namespaced and self.namespace and not metadata.get('namespace'): + metadata['namespace'] = self.namespace + definition['metadata'] = metadata return definition def perform_action(self, resource, definition): @@ -197,12 +214,6 @@ class KubernetesRawModule(KubernetesAnsibleModule): self.remove_aliases() - if definition['kind'].endswith('List'): - result['result'] = resource.get(namespace=namespace).to_dict() - result['changed'] = False - result['method'] = 'get' - return result - try: # ignore append_hash for resources other than ConfigMap and Secret if self.append_hash and definition['kind'] in ['ConfigMap', 'Secret']: diff --git a/test/integration/targets/k8s/playbooks/roles/k8s/tasks/lists.yml b/test/integration/targets/k8s/playbooks/roles/k8s/tasks/lists.yml new file mode 100644 index 00000000000..dfdc53301b4 --- /dev/null +++ b/test/integration/targets/k8s/playbooks/roles/k8s/tasks/lists.yml @@ -0,0 +1,140 @@ +--- + +- name: Ensure testing1 namespace exists + k8s: + api_version: v1 + kind: Namespace + name: testing1 + +- block: + - name: Create configmaps + k8s: + namespace: testing1 + definition: + apiVersion: v1 + kind: ConfigMapList + items: '{{ configmaps }}' + + - name: Get ConfigMaps + k8s_facts: + api_version: v1 + kind: ConfigMap + namespace: testing1 + label_selectors: + - app=test + register: cms + + - name: All three configmaps should exist + assert: + that: item.data.a is defined + with_items: '{{ cms.resources }}' + + - name: Delete configmaps + k8s: + state: absent + namespace: testing1 + definition: + apiVersion: v1 + kind: ConfigMapList + items: '{{ configmaps }}' + + - name: Get ConfigMaps + k8s_facts: + api_version: v1 + kind: ConfigMap + namespace: testing1 + label_selectors: + - app=test + register: cms + + - name: All three configmaps should not exist + assert: + that: not cms.resources + vars: + configmaps: + - metadata: + name: list-example-1 + labels: + app: test + data: + a: first + - metadata: + name: list-example-2 + labels: + app: test + data: + a: second + - metadata: + name: list-example-3 + labels: + app: test + data: + a: third + +- block: + - name: Create list of arbitrary resources + k8s: + namespace: testing1 + definition: + apiVersion: v1 + kind: List + namespace: testing1 + items: '{{ resources }}' + + - name: Get the created resources + k8s_facts: + api_version: '{{ item.apiVersion }}' + kind: '{{ item.kind }}' + namespace: testing1 + name: '{{ item.metadata.name }}' + register: list_resources + with_items: '{{ resources }}' + + - name: All resources should exist + assert: + that: ((list_resources.results | sum(attribute="resources", start=[])) | length) == (resources | length) + + - name: Delete list of arbitrary resources + k8s: + state: absent + namespace: testing1 + definition: + apiVersion: v1 + kind: List + namespace: testing1 + items: '{{ resources }}' + + - name: Get the resources + k8s_facts: + api_version: '{{ item.apiVersion }}' + kind: '{{ item.kind }}' + namespace: testing1 + name: '{{ item.metadata.name }}' + register: list_resources + with_items: '{{ resources }}' + + - name: The resources should not exist + assert: + that: not ((list_resources.results | sum(attribute="resources", start=[])) | length) + vars: + resources: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: list-example-4 + data: + key: value + - apiVersion: v1 + kind: Service + metadata: + name: list-example-svc + labels: + app: test + spec: + selector: + app: test + ports: + - protocol: TCP + targetPort: 8000 + name: port-8000-tcp + port: 8000 diff --git a/test/integration/targets/k8s/playbooks/roles/k8s/tasks/main.yml b/test/integration/targets/k8s/playbooks/roles/k8s/tasks/main.yml index fa5823bd673..de936660a1c 100644 --- a/test/integration/targets/k8s/playbooks/roles/k8s/tasks/main.yml +++ b/test/integration/targets/k8s/playbooks/roles/k8s/tasks/main.yml @@ -285,6 +285,7 @@ loop: "{{ k8s_facts.results }}" - include_tasks: crd.yml + - include_tasks: lists.yml - include_tasks: append_hash.yml always: