Skip to content

Commit 151ed82

Browse files
authored
make name optional to delete all resources for the specified resource type (#517)
make name optional to delete all resources for the specified resource type SUMMARY closes #504 k8s module should allow deleting all namespace resources for the specified resource type. ISSUE TYPE Feature Pull Request COMPONENT NAME k8s ADDITIONAL INFORMATION Delete all Pods from namespace test - k8s: namespace: test kind: Pod api_version: v1 delete_all: true state: absent Reviewed-by: Gonéri Le Bouder <[email protected]> Reviewed-by: Mike Graves <[email protected]> Reviewed-by: Bikouo Aubin
1 parent 09a3c83 commit 151ed82

File tree

11 files changed

+235
-5
lines changed

11 files changed

+235
-5
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
minor_changes:
3+
- 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)

plugins/module_utils/k8s/runner.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,51 @@ def _prepend_resource_info(resource, msg):
4646
return [_prepend_resource_info(resource, msg) for msg in warnings + errors]
4747

4848

49+
def get_definitions(svc, params):
50+
try:
51+
definitions = create_definitions(params)
52+
except Exception as e:
53+
msg = "Failed to load resource definition: {0}".format(e)
54+
raise CoreException(msg) from e
55+
56+
delete_all = params.get("delete_all")
57+
src = params.get("src")
58+
resource_definition = params.get("resource_definition")
59+
name = params.get("name")
60+
state = params.get("state")
61+
62+
if (
63+
delete_all
64+
and state == "absent"
65+
and name is None
66+
and resource_definition is None
67+
and src is None
68+
):
69+
# Delete all resources in the namespace for the specified resource type
70+
if params.get("kind") is None:
71+
raise CoreException(
72+
"'kind' option is required to specify the resource type."
73+
)
74+
75+
resource = svc.find_resource(
76+
params.get("kind"), params.get("api_version"), fail=True
77+
)
78+
definitions = svc.retrieve_all(
79+
resource,
80+
params.get("namespace"),
81+
params.get("label_selectors"),
82+
)
83+
84+
return definitions
85+
86+
4987
def run_module(module) -> None:
5088
results = []
5189
changed = False
5290
client = get_api_client(module)
5391
svc = K8sService(client, module)
54-
try:
55-
definitions = create_definitions(module.params)
56-
except Exception as e:
57-
msg = "Failed to load resource definition: {0}".format(e)
58-
raise CoreException(msg) from e
92+
93+
definitions = get_definitions(svc, module.params)
5994

6095
for definition in definitions:
6196
result = {"changed": False, "result": {}}

plugins/module_utils/k8s/service.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,30 @@ def retrieve(self, resource: Resource, definition: Dict) -> ResourceInstance:
211211

212212
return existing
213213

214+
def retrieve_all(
215+
self, resource: Resource, namespace: str, label_selectors: List[str] = None
216+
) -> List[Dict]:
217+
definitions: List[ResourceInstance] = []
218+
219+
try:
220+
params = dict(namespace=namespace)
221+
if label_selectors:
222+
params["label_selector"] = ",".join(label_selectors)
223+
resource_list = self.client.get(resource, **params)
224+
for item in resource_list.items:
225+
existing = self.client.get(
226+
resource, name=item.metadata.name, namespace=namespace
227+
)
228+
definitions.append(existing.to_dict())
229+
except (NotFoundError, MethodNotAllowedError):
230+
pass
231+
except Exception as e:
232+
reason = e.body if hasattr(e, "body") else e
233+
msg = "Failed to retrieve requested object: {0}".format(reason)
234+
raise CoreException(msg) from e
235+
236+
return definitions
237+
214238
def find(
215239
self,
216240
kind: str,

plugins/modules/k8s.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,19 @@
172172
- When set to True, server-side apply will force the changes against conflicts.
173173
type: bool
174174
default: False
175+
delete_all:
176+
description:
177+
- When this option is set to I(true) and I(state=absent),
178+
module will delete all resources of the specified resource type in the requested namespace.
179+
- Ignored when C(state) is not set to I(absent) or when one of (src),
180+
C(name) or C(resource_definition) is provided.
181+
- Parameter C(kind) is required to use this option.
182+
- This parameter can be used with C(label_selectors) to restrict the resources to be deleted.
183+
type: bool
184+
default: false
185+
version_added: 2.5.0
186+
aliases:
187+
- all
175188
176189
requirements:
177190
- "python >= 3.6"
@@ -343,6 +356,14 @@
343356
apply: yes
344357
server_side_apply:
345358
field_manager: ansible
359+
360+
# Delete all Deployment from specified namespace
361+
- name: Delete all Deployment from specified namespace
362+
kubernetes.core.k8s:
363+
api_version: apps/v1
364+
namespace: testing
365+
kind: Deployment
366+
delete_all: true
346367
"""
347368

348369
RETURN = r"""
@@ -450,6 +471,7 @@ def argspec():
450471
argument_spec["server_side_apply"] = dict(
451472
type="dict", default=None, options=server_apply_spec()
452473
)
474+
argument_spec["delete_all"] = dict(type="bool", default=False, aliases=["all"])
453475

454476
return argument_spec
455477

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
apiVersion: apps/v1
3+
kind: Deployment
4+
metadata:
5+
name: nginx-d
6+
labels:
7+
context: ansible
8+
spec:
9+
replicas: 1
10+
selector:
11+
matchLabels:
12+
context: ansible
13+
template:
14+
metadata:
15+
labels:
16+
context: ansible
17+
spec:
18+
containers:
19+
- name: nginx
20+
image: nginx
21+
ports:
22+
- containerPort: 80
23+
---
24+
apiVersion: apps/v1
25+
kind: Deployment
26+
metadata:
27+
name: openjdk-d
28+
labels:
29+
context: ansible
30+
spec:
31+
replicas: 2
32+
selector:
33+
matchLabels:
34+
context: ansible
35+
template:
36+
metadata:
37+
labels:
38+
context: ansible
39+
spec:
40+
containers:
41+
- name: openjdk
42+
image: openjdk:17
43+
command:
44+
- /bin/sh
45+
- -c
46+
- while true;do date;sleep 5; done
47+
---
48+
apiVersion: apps/v1
49+
kind: Deployment
50+
metadata:
51+
name: alpine-d
52+
labels:
53+
context: ansible
54+
spec:
55+
replicas: 3
56+
selector:
57+
matchLabels:
58+
context: ansible
59+
template:
60+
metadata:
61+
labels:
62+
context: ansible
63+
spec:
64+
containers:
65+
- name: alpine
66+
image: alpine
67+
command:
68+
- /bin/sh
69+
- -c
70+
- while true;do date;sleep 5; done

tests/integration/targets/k8s_delete/tasks/main.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,77 @@
121121
that:
122122
- _result.resources | length == 0
123123

124+
# test deletion using delete_all=true
125+
- name: Create deployments
126+
k8s:
127+
namespace: "{{ test_namespace }}"
128+
src: files/deployments.yaml
129+
wait: true
130+
register: result
131+
132+
- name: Trying to delete deployments without name and label_selectors and select_all=false
133+
k8s:
134+
kind: Deployment
135+
api_version: apps/v1
136+
namespace: "{{ test_namespace }}"
137+
state: absent
138+
register: _delete
139+
140+
- name: Ensure Deployment were not deleted
141+
assert:
142+
that:
143+
- _delete is not changed
144+
145+
- name: Validate that Deployment still exist
146+
k8s_info:
147+
kind: Deployment
148+
api_version: apps/v1
149+
namespace: "{{ test_namespace }}"
150+
label_selectors:
151+
- context=ansible
152+
register: _deployment
153+
failed_when: _deployment.resources | length == 0
154+
155+
- name: Trying to delete using delete_all=true but missing kind option
156+
k8s:
157+
api_version: apps/v1
158+
namespace: "{{ test_namespace }}"
159+
delete_all: true
160+
state: absent
161+
register: _delete
162+
ignore_errors: true
163+
164+
- name: assert task failed with proper message
165+
assert:
166+
that:
167+
- _delete is failed
168+
- _delete.msg == "'kind' option is required to specify the resource type."
169+
170+
- name: Trying to delete deployments without name and label_selectors and delete_all=true
171+
k8s:
172+
kind: Deployment
173+
api_version: apps/v1
174+
namespace: "{{ test_namespace }}"
175+
delete_all: true
176+
wait: true
177+
state: absent
178+
register: _delete
179+
180+
- name: Ensure Deployment were deleted
181+
assert:
182+
that:
183+
- _delete is changed
184+
185+
- name: Validate that Deployment do not exist anymore
186+
k8s_info:
187+
kind: Deployment
188+
api_version: apps/v1
189+
namespace: "{{ test_namespace }}"
190+
label_selectors:
191+
- context=ansible
192+
register: _deployment
193+
failed_when: _deployment.resources | length > 0
194+
124195
always:
125196
- name: Remove namespace
126197
k8s:

tests/sanity/ignore-2.11.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,3 +590,4 @@ tests/integration/targets/setup_kubeconfig/library/test_inventory_read_credentia
590590
tests/integration/targets/helm/library/helm_test_version.py compile-2.6!skip
591591
tests/integration/targets/helm/library/helm_test_version.py compile-2.7!skip
592592
tests/integration/targets/helm/library/helm_test_version.py compile-3.5!skip
593+
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip

tests/sanity/ignore-2.12.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ plugins/modules/k8s.py validate-modules:return-syntax-error
3030
plugins/modules/k8s_scale.py validate-modules:return-syntax-error
3131
plugins/modules/k8s_service.py validate-modules:return-syntax-error
3232
plugins/modules/k8s_taint.py validate-modules:return-syntax-error
33+
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip

tests/sanity/ignore-2.13.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ plugins/modules/k8s.py validate-modules:return-syntax-error
3030
plugins/modules/k8s_scale.py validate-modules:return-syntax-error
3131
plugins/modules/k8s_service.py validate-modules:return-syntax-error
3232
plugins/modules/k8s_taint.py validate-modules:return-syntax-error
33+
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip

tests/sanity/ignore-2.14.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ plugins/modules/k8s.py validate-modules:return-syntax-error
3030
plugins/modules/k8s_scale.py validate-modules:return-syntax-error
3131
plugins/modules/k8s_service.py validate-modules:return-syntax-error
3232
plugins/modules/k8s_taint.py validate-modules:return-syntax-error
33+
tests/integration/targets/k8s_delete/files/deployments.yaml yamllint!skip

0 commit comments

Comments
 (0)