Skip to content

Commit 09a3c83

Browse files
authored
[helm] add the ability for the module to uninstall pending-install releases (#589)
[helm] add the ability for the module to uninstall pending-install releases SUMMARY closes #319 ISSUE TYPE Feature Pull Request COMPONENT NAME helm Reviewed-by: Mike Graves <[email protected]> Reviewed-by: Bikouo Aubin
1 parent 31c1ccf commit 09a3c83

File tree

4 files changed

+194
-23
lines changed

4 files changed

+194
-23
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
bugfixes:
3+
- helm - fix issue occurring when uninstalling chart with statues others than 'deployed' (https://github.com/ansible-collections/kubernetes.core/issues/319).

plugins/modules/helm.py

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -432,14 +432,20 @@ def get_release(state, release_name):
432432
return None
433433

434434

435-
def get_release_status(module, release_name):
435+
def get_release_status(module, release_name, all_status=False):
436436
"""
437-
Get Release state from deployed release
437+
Get Release state from all release status (deployed, failed, pending-install, etc)
438438
"""
439439

440-
list_command = (
441-
module.get_helm_binary() + " list --output=yaml --filter " + release_name
442-
)
440+
list_command = [
441+
module.get_helm_binary(),
442+
"list",
443+
"--output=yaml",
444+
"--filter",
445+
release_name,
446+
]
447+
if all_status:
448+
list_command.append("--all")
443449

444450
rc, out, err = module.run_helm_command(list_command)
445451

@@ -773,29 +779,31 @@ def main():
773779
run_repo_update(module)
774780

775781
# Get real/deployed release status
776-
release_status = get_release_status(module, release_name)
782+
all_status = release_state == "absent"
783+
release_status = get_release_status(module, release_name, all_status=all_status)
777784

778785
helm_cmd = module.get_helm_binary()
779786
opt_result = {}
780787
if release_state == "absent" and release_status is not None:
781-
if replace:
782-
module.fail_json(msg="replace is not applicable when state is absent")
783-
784-
if wait:
785-
helm_version = module.get_helm_version()
786-
if LooseVersion(helm_version) < LooseVersion("3.7.0"):
787-
opt_result["warnings"] = []
788-
opt_result["warnings"].append(
789-
"helm uninstall support option --wait for helm release >= 3.7.0"
790-
)
791-
wait = False
788+
# skip release statuses 'uninstalled' and 'uninstalling'
789+
if not release_status["status"].startswith("uninstall"):
790+
if replace:
791+
module.fail_json(msg="replace is not applicable when state is absent")
792+
793+
if wait:
794+
helm_version = module.get_helm_version()
795+
if LooseVersion(helm_version) < LooseVersion("3.7.0"):
796+
opt_result["warnings"] = []
797+
opt_result["warnings"].append(
798+
"helm uninstall support option --wait for helm release >= 3.7.0"
799+
)
800+
wait = False
792801

793-
helm_cmd = delete(
794-
helm_cmd, release_name, purge, disable_hook, wait, wait_timeout
795-
)
796-
changed = True
802+
helm_cmd = delete(
803+
helm_cmd, release_name, purge, disable_hook, wait, wait_timeout
804+
)
805+
changed = True
797806
elif release_state == "present":
798-
799807
if chart_version is not None:
800808
helm_cmd += " --version=" + chart_version
801809

@@ -956,7 +964,7 @@ def main():
956964
changed=changed,
957965
stdout=out,
958966
stderr=err,
959-
status=get_release_status(module, release_name),
967+
status=get_release_status(module, release_name, all_status=True),
960968
command=helm_cmd,
961969
**opt_result,
962970
)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright: (c) 2023, Ansible Project
5+
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6+
from __future__ import absolute_import, division, print_function
7+
8+
__metaclass__ = type
9+
10+
11+
DOCUMENTATION = r"""
12+
---
13+
module: helm_test_pending
14+
short_description: created pending-install release
15+
author:
16+
- Aubin Bikouo (@abikouo)
17+
requirements:
18+
- "helm (https://github.com/helm/helm/releases)"
19+
description:
20+
- This module is used to create a pending install release for integration testing
21+
- The scope of this module is the integration testing of the kubernetes.core collection only.
22+
options:
23+
binary_path:
24+
description:
25+
- The path of a helm binary to use.
26+
required: true
27+
type: path
28+
chart_ref:
29+
description:
30+
- chart reference on chart repository (e.g. my-repo/my-chart-ref)
31+
required: true
32+
type: str
33+
chart_release:
34+
description:
35+
- Release name to manage.
36+
required: true
37+
type: str
38+
chart_release_namespace:
39+
description:
40+
- Kubernetes namespace where the chart should be installed.
41+
required: true
42+
type: str
43+
"""
44+
45+
EXAMPLES = r"""
46+
"""
47+
48+
RETURN = r"""
49+
"""
50+
51+
import subprocess
52+
import json
53+
import time
54+
from ansible.module_utils.basic import AnsibleModule
55+
56+
57+
class HelmReleaseNotFoundError(Exception):
58+
def __init__(self, message):
59+
super().__init__(message)
60+
61+
62+
def create_pending_install_release(helm_binary, chart_ref, chart_release, namespace):
63+
# create pending-install release
64+
command = [
65+
helm_binary,
66+
"install",
67+
chart_release,
68+
chart_ref,
69+
"--namespace",
70+
namespace,
71+
"--wait",
72+
]
73+
proc = subprocess.Popen(command)
74+
time.sleep(2)
75+
proc.kill()
76+
# ensure release status is pending-install
77+
command = [
78+
helm_binary,
79+
"list",
80+
"--all",
81+
"--output=json",
82+
"--namespace",
83+
namespace,
84+
"--filter",
85+
chart_release,
86+
]
87+
cmd = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
88+
out, err = cmd.communicate()
89+
90+
data = json.loads(out)
91+
if not data:
92+
error = "Release %s not found." % chart_release
93+
raise HelmReleaseNotFoundError(message=error)
94+
return data[0]["status"] == "pending-install", data[0]["status"]
95+
96+
97+
def main():
98+
module = AnsibleModule(
99+
argument_spec=dict(
100+
binary_path=dict(type="path", required=True),
101+
chart_ref=dict(type="str", required=True),
102+
chart_release=dict(type="str", required=True),
103+
chart_release_namespace=dict(type="str", required=True),
104+
),
105+
)
106+
107+
params = dict(
108+
helm_binary=module.params.get("binary_path"),
109+
chart_release=module.params.get("chart_release"),
110+
chart_ref=module.params.get("chart_ref"),
111+
namespace=module.params.get("chart_release_namespace"),
112+
)
113+
114+
try:
115+
result, status = create_pending_install_release(**params)
116+
if not result:
117+
module.fail_json(
118+
msg="unable to create pending-install release, current status is %s"
119+
% status
120+
)
121+
module.exit_json(changed=True, msg="Release created with status '%s'" % status)
122+
except HelmReleaseNotFoundError as err:
123+
module.fail_json(
124+
msg="Error while trying to create pending-install release due to '%s'" % err
125+
)
126+
127+
128+
if __name__ == "__main__":
129+
main()

tests/integration/targets/helm/tasks/test_helm_uninstall.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- vars:
88
chart_source: "https://github.com/kubernetes/kube-state-metrics/releases/download/kube-state-metrics-helm-chart-2.13.3/kube-state-metrics-2.13.3.tgz"
99
chart_name: "test-wait-uninstall"
10+
chart_name_pending: "test-uninstall-pending-release"
1011
helm_namespace: "{{ test_namespace[1] }}"
1112
block:
1213

@@ -64,6 +65,36 @@
6465
wait: yes
6566
register: uninstall
6667

68+
# Test uninstall chart release with 'pending-install' status
69+
- name: Create chart release with 'pending-install' status
70+
helm_test_pending:
71+
binary_path: "{{ helm_binary }}"
72+
chart_ref: "{{ chart_source }}"
73+
chart_release: "{{ chart_name_pending }}"
74+
chart_release_namespace: "{{ helm_namespace }}"
75+
76+
- name: Uninstall chart release with 'pending-install' status
77+
helm:
78+
binary_path: "{{ helm_binary }}"
79+
release_name: "{{ chart_name_pending }}"
80+
namespace: "{{ helm_namespace }}"
81+
release_state: absent
82+
register: _uninstall
83+
84+
- name: Get Helm release details
85+
helm_info:
86+
binary_path: "{{ helm_binary }}"
87+
release_namespace: "{{ helm_namespace }}"
88+
release_state: pending
89+
release_name: "{{ chart_name_pending }}"
90+
register: _info
91+
92+
- name: assert release does not exist anymore
93+
assert:
94+
that:
95+
- _uninstall is changed
96+
- _info.status is undefined
97+
6798
always:
6899
- name: Delete temp directory
69100
file:

0 commit comments

Comments
 (0)