diff --git a/changelogs/fragments/517-k8s-make-name-optional.yaml b/changelogs/fragments/517-k8s-make-name-optional.yaml index 378a12b0e4..e7ef01de69 100644 --- a/changelogs/fragments/517-k8s-make-name-optional.yaml +++ b/changelogs/fragments/517-k8s-make-name-optional.yaml @@ -1,3 +1,3 @@ --- minor_changes: - - k8s - make name optional when trying to delete or patch all resources from namespace. (https://github.com/ansible-collections/kubernetes.core/issues/504) + - k8s - add new option delete_all to support deletion of all resources when state is set to absent. (https://github.com/ansible-collections/kubernetes.core/issues/504) diff --git a/plugins/module_utils/k8s/runner.py b/plugins/module_utils/k8s/runner.py index bb1a8680d8..afb1c9d276 100644 --- a/plugins/module_utils/k8s/runner.py +++ b/plugins/module_utils/k8s/runner.py @@ -25,7 +25,6 @@ from ansible_collections.kubernetes.core.plugins.module_utils.selector import ( LabelSelectorFilter, ) -from ansible.module_utils.common.dict_transformations import dict_merge def validate(client, module, resource): @@ -47,65 +46,51 @@ def _prepend_resource_info(resource, msg): return [_prepend_resource_info(resource, msg) for msg in warnings + errors] -def run_module(module) -> None: - results = [] - changed = False - client = get_api_client(module) - svc = K8sService(client, module) +def get_definitions(svc, params): try: - definitions = create_definitions(module.params) + definitions = create_definitions(params) except Exception as e: msg = "Failed to load resource definition: {0}".format(e) raise CoreException(msg) from e - select_all = module.params.get("select_all") - src = module.params.get("src") - resource_definition = module.params.get("resource_definition") - name = module.params.get("name") - state = module.params.get("state") + delete_all = params.get("delete_all") + src = params.get("src") + resource_definition = params.get("resource_definition") + name = params.get("name") + state = params.get("state") if ( - state == "absent" + delete_all + and state == "absent" and name is None and resource_definition is None and src is None - and select_all ): # Delete all resources in the namespace for the specified resource type - if module.params.get("kind") is None: + if params.get("kind") is None: raise CoreException( "'kind' option is required to sepcify the resource type." ) resource = svc.find_resource( - module.params.get("kind"), module.params.get("api_version"), fail=True + params.get("kind"), params.get("api_version"), fail=True ) definitions = svc.retrieve_all( resource, - module.params.get("namespace"), - module.params.get("label_selectors"), + params.get("namespace"), + params.get("label_selectors"), ) - elif ( - state == "patched" - and select_all - and len(definitions) == 1 - and definitions[0].get("metadata", {}).get("name") is None - ): - kind = definitions[0].get("kind") or module.params.get("kind") - api_version = module.params.get("apiVersion") or definitions[0].get( - "api_version" - ) - if kind is None: - raise CoreException( - "'kind' option is required to sepcify the resource type." - ) - resource = svc.find_resource(kind, api_version, fail=True) - existing = svc.retrieve_all( - resource, - module.params.get("namespace"), - module.params.get("label_selectors"), - ) - definitions = [dict_merge(d, definitions[0]) for d in existing] + + return definitions + + +def run_module(module) -> None: + results = [] + changed = False + client = get_api_client(module) + svc = K8sService(client, module) + + definitions = get_definitions(svc, module.params) for definition in definitions: result = {"changed": False, "result": {}} diff --git a/plugins/modules/k8s.py b/plugins/modules/k8s.py index 24cda75539..3ae493cad5 100644 --- a/plugins/modules/k8s.py +++ b/plugins/modules/k8s.py @@ -172,18 +172,16 @@ - When set to True, server-side apply will force the changes against conflicts. type: bool default: False - select_all: + delete_all: description: - - When this option is set to I(true), action will be performed on all resources, in the namespace of the specified resource type. - - When I(select_all=True) and I(state=absent), C(kind) is required. - - When I(select_all=True) and I(state=patched) a valid YAML definition must be provided using option C(src) or C(resource_definition), - resource type must be defined using C(kind) option or into provided YAML definition. - - Ignored when I(state=present). - - Ignored when I(state=absent) and one of C(src), C(name) or C(resource_definition) is provided. - - Ignored when I(state=patched) and C(name) is provided or C(src) or C(resource_definition) is provided with a list containing - more than one YAML definition, or if the resource definition contains a metadata.name field. + - When this option is set to I(true) and I(state=absent), + module will delete on all resources, in the namespace of the specified resource type. + - Ignored when C(state) is not set to I(absent) or when one of (src), + C(name) or C(resource_definition) is provided. + - Parameter C(kind) is required to use this option. type: bool default: false + version_added: 2.5.0 aliases: - all @@ -364,18 +362,7 @@ api_version: apps/v1 namespace: testing kind: Deployment - select_all: true - -# Pause all Deployment from specified namespace -- name: Delete all Deployment from specified namespace - kubernetes.core.k8s: - api_version: apps/v1 - namespace: testing - kind: Deployment - definition: - spec: - paused: True - select_all: true + delete_all: true """ RETURN = r""" @@ -483,7 +470,7 @@ def argspec(): argument_spec["server_side_apply"] = dict( type="dict", default=None, options=server_apply_spec() ) - argument_spec["select_all"] = dict(type="bool", default=False, aliases=["all"]) + argument_spec["delete_all"] = dict(type="bool", default=False, aliases=["all"]) return argument_spec diff --git a/plugins/modules/k8s_log.py b/plugins/modules/k8s_log.py index 0fd8abd06a..e52d5bce7b 100644 --- a/plugins/modules/k8s_log.py +++ b/plugins/modules/k8s_log.py @@ -267,10 +267,19 @@ def execute_module(svc, params): {"tailLines": params["tail_lines"]} ) + pod_containers = [None] + if params.get("all_containers"): + pod_containers = list_containers_in_pod(svc, resource, namespace, name) + + log = "" try: - response = resource.log.get( - name=name, namespace=namespace, serialize=False, **kwargs - ) + for container in pod_containers: + if container is not None: + kwargs.setdefault("query_params", {}).update({"container": container}) + response = resource.log.get( + name=name, namespace=namespace, serialize=False, **kwargs + ) + log += response.data.decode("utf8") except ApiException as exc: if exc.reason == "Not Found": raise CoreException("Pod {0}/{1} not found.".format(namespace, name)) diff --git a/tests/integration/targets/k8s_delete/tasks/main.yml b/tests/integration/targets/k8s_delete/tasks/main.yml index 80449b43a0..f35b7ee446 100644 --- a/tests/integration/targets/k8s_delete/tasks/main.yml +++ b/tests/integration/targets/k8s_delete/tasks/main.yml @@ -121,7 +121,7 @@ that: - _result.resources | length == 0 - # test deletion using select_all=true + # test deletion using delete_all=true - name: Create deployments k8s: namespace: "{{ test_namespace }}" @@ -152,11 +152,11 @@ register: _deployment failed_when: _deployment.resources | length == 0 - - name: Trying to delete using select_all=true but missing kind option + - name: Trying to delete using delete_all=true but missing kind option k8s: api_version: apps/v1 namespace: "{{ test_namespace }}" - select_all: true + delete_all: true state: absent register: _delete ignore_errors: true @@ -167,12 +167,12 @@ - _delete is failed - _delete.msg == "'kind' option is required to sepcify the resource type." - - name: Trying to delete deployments without name and label_selectors and select_all=true + - name: Trying to delete deployments without name and label_selectors and delete_all=true k8s: kind: Deployment api_version: apps/v1 namespace: "{{ test_namespace }}" - select_all: true + delete_all: true wait: true state: absent register: _delete diff --git a/tests/integration/targets/k8s_patched/files/deployments.yaml b/tests/integration/targets/k8s_patched/files/deployments.yaml deleted file mode 100644 index a3e6a81588..0000000000 --- a/tests/integration/targets/k8s_patched/files/deployments.yaml +++ /dev/null @@ -1,70 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx - labels: - context: ansible -spec: - replicas: 1 - selector: - matchLabels: - context: ansible - template: - metadata: - labels: - context: ansible - spec: - containers: - - name: nginx - image: nginx - ports: - - containerPort: 80 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: openjdk - labels: - context: ansible -spec: - replicas: 2 - selector: - matchLabels: - context: ansible - template: - metadata: - labels: - context: ansible - spec: - containers: - - name: openjdk - image: openjdk:17 - command: - - /bin/sh - - -c - - while true;do date;sleep 5; done ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: alpine - labels: - context: ansible -spec: - replicas: 3 - selector: - matchLabels: - context: ansible - template: - metadata: - labels: - context: ansible - spec: - containers: - - name: alpine - image: alpine - command: - - /bin/sh - - -c - - while true;do date;sleep 5; done diff --git a/tests/integration/targets/k8s_patched/tasks/main.yml b/tests/integration/targets/k8s_patched/tasks/main.yml index f2cdbf5efd..8846d06418 100644 --- a/tests/integration/targets/k8s_patched/tasks/main.yml +++ b/tests/integration/targets/k8s_patched/tasks/main.yml @@ -109,149 +109,6 @@ that: - second_namespace.resources | length == 1 - # test Patch for all resources from namespace - - name: Create deployments - k8s: - namespace: "{{ patch_only_namespace[0] }}" - src: files/deployments.yaml - wait: true - register: result - - - name: Patch all deployments using label_selectors - k8s: - namespace: "{{ patch_only_namespace[0] }}" - kind: Deployment - api_version: apps/v1 - label_selectors: - - context=ansible - state: patched - definition: - metadata: - labels: - patched: "true" - register: _patch - - - name: Ensure task is changed - assert: - that: - - _patch is changed - - - name: Retrieve deployments - k8s_info: - api_version: apps/v1 - kind: Deployment - namespace: "{{ patch_only_namespace[0] }}" - label_selectors: - - context=ansible - register: _deployments - failed_when: _deployments.resources | length != 3 - - - name: Ensure all deployments were patched - assert: - that: - - '"patched" in item.metadata.labels' - - 'item.metadata.labels.patched == "true"' - with_items: "{{ _deployments.resources }}" - - - name: Trying to patch using select_all=true but missing resource type - k8s: - namespace: "{{ patch_only_namespace[0] }}" - api_version: apps/v1 - select_all: true - state: patched - definition: - spec: - template: - spec: - containers: - - name: container2 - image: redis - register: _patch - ignore_errors: true - - - name: assert task failed with proper message - assert: - that: - - _patch is failed - - _patch.msg == "'kind' option is required to sepcify the resource type." - - - name: Patch all deployments using select_all=true - k8s: - namespace: "{{ patch_only_namespace[0] }}" - kind: Deployment - api_version: apps/v1 - select_all: true - state: patched - definition: - spec: - template: - spec: - containers: - - name: container2 - image: redis - register: _patch - - - name: Ensure task is changed - assert: - that: - - _patch is changed - - - name: Retrieve deployments - k8s_info: - api_version: apps/v1 - kind: Deployment - namespace: "{{ patch_only_namespace[0] }}" - label_selectors: - - context=ansible - register: _deployments - failed_when: _deployments.resources | length != 3 - - - name: Ensure all deployments were patched - assert: - that: - - item.spec.template.spec.containers | length == 2 - - '"container2" in item.spec.template.spec.containers | map(attribute="name") | list' - with_items: "{{ _deployments.resources }}" - - - name: Patch deployment using select_all=true and name (should patched only specified deployment) - k8s: - namespace: "{{ patch_only_namespace[0] }}" - kind: Deployment - api_version: apps/v1 - select_all: true - state: patched - definition: - metadata: - name: alpine - spec: - template: - spec: - containers: - - name: container3 - image: httpd - register: _patch - - - name: Ensure task is changed - assert: - that: - - _patch is changed - - - name: Ensure only alpine deployment was patched - k8s_info: - api_version: apps/v1 - kind: Deployment - namespace: "{{ patch_only_namespace[0] }}" - name: "{{ item.name }}" - register: _deployment - failed_when: _deployment.resources.0.spec.template.spec.containers | length != item.containers - with_items: - - name: alpine - containers: 3 - - name: openjdk - containers: 2 - - name: nginx - containers: 2 - always: - name: Remove namespace kubernetes.core.k8s: diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index 8ef944877e..ffd29612e4 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -590,5 +590,4 @@ tests/integration/targets/setup_kubeconfig/library/test_inventory_read_credentia tests/integration/targets/helm/library/helm_test_version.py compile-2.6!skip tests/integration/targets/helm/library/helm_test_version.py compile-2.7!skip tests/integration/targets/helm/library/helm_test_version.py compile-3.5!skip -tests/integration/targets/k8s_patched/files/deployments.yaml yamllint!skip tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip diff --git a/tests/sanity/ignore-2.12.txt b/tests/sanity/ignore-2.12.txt index 02b8161c78..c0d1d58963 100644 --- a/tests/sanity/ignore-2.12.txt +++ b/tests/sanity/ignore-2.12.txt @@ -30,5 +30,4 @@ plugins/modules/k8s.py validate-modules:return-syntax-error plugins/modules/k8s_scale.py validate-modules:return-syntax-error plugins/modules/k8s_service.py validate-modules:return-syntax-error plugins/modules/k8s_taint.py validate-modules:return-syntax-error -tests/integration/targets/k8s_patched/files/deployments.yaml yamllint!skip tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip diff --git a/tests/sanity/ignore-2.13.txt b/tests/sanity/ignore-2.13.txt index 02b8161c78..c0d1d58963 100644 --- a/tests/sanity/ignore-2.13.txt +++ b/tests/sanity/ignore-2.13.txt @@ -30,5 +30,4 @@ plugins/modules/k8s.py validate-modules:return-syntax-error plugins/modules/k8s_scale.py validate-modules:return-syntax-error plugins/modules/k8s_service.py validate-modules:return-syntax-error plugins/modules/k8s_taint.py validate-modules:return-syntax-error -tests/integration/targets/k8s_patched/files/deployments.yaml yamllint!skip tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 02b8161c78..c0d1d58963 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -30,5 +30,4 @@ plugins/modules/k8s.py validate-modules:return-syntax-error plugins/modules/k8s_scale.py validate-modules:return-syntax-error plugins/modules/k8s_service.py validate-modules:return-syntax-error plugins/modules/k8s_taint.py validate-modules:return-syntax-error -tests/integration/targets/k8s_patched/files/deployments.yaml yamllint!skip tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip diff --git a/tests/sanity/refresh_ignore_files b/tests/sanity/refresh_ignore_files index 98ac365f74..d06fb31e2a 100644 --- a/tests/sanity/refresh_ignore_files +++ b/tests/sanity/refresh_ignore_files @@ -48,7 +48,6 @@ YAML_LINT_SKIPS = [ "tests/integration/targets/helm/files/test-chart/templates/configmap.yaml", "tests/integration/targets/helm_diff/files/test-chart/templates/configmap.yaml", "tests/integration/targets/k8s_scale/files/deployment.yaml", - "tests/integration/targets/k8s_patched/files/deployments.yaml", "tests/integration/targets/k8s_delete/files/deployments.yaml", ]