Skip to content

Commit

Permalink
[helm] add the ability for the module to uninstall pending-install re…
Browse files Browse the repository at this point in the history
…leases (#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 <mgraves@redhat.com>
Reviewed-by: Bikouo Aubin
  • Loading branch information
abikouo authored Mar 6, 2023
1 parent 31c1ccf commit 09a3c83
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
bugfixes:
- helm - fix issue occurring when uninstalling chart with statues others than 'deployed' (https://github.com/ansible-collections/kubernetes.core/issues/319).
54 changes: 31 additions & 23 deletions plugins/modules/helm.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,14 +432,20 @@ def get_release(state, release_name):
return None


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

list_command = (
module.get_helm_binary() + " list --output=yaml --filter " + release_name
)
list_command = [
module.get_helm_binary(),
"list",
"--output=yaml",
"--filter",
release_name,
]
if all_status:
list_command.append("--all")

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

Expand Down Expand Up @@ -773,29 +779,31 @@ def main():
run_repo_update(module)

# Get real/deployed release status
release_status = get_release_status(module, release_name)
all_status = release_state == "absent"
release_status = get_release_status(module, release_name, all_status=all_status)

helm_cmd = module.get_helm_binary()
opt_result = {}
if release_state == "absent" and release_status is not None:
if replace:
module.fail_json(msg="replace is not applicable when state is absent")

if wait:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.7.0"):
opt_result["warnings"] = []
opt_result["warnings"].append(
"helm uninstall support option --wait for helm release >= 3.7.0"
)
wait = False
# skip release statuses 'uninstalled' and 'uninstalling'
if not release_status["status"].startswith("uninstall"):
if replace:
module.fail_json(msg="replace is not applicable when state is absent")

if wait:
helm_version = module.get_helm_version()
if LooseVersion(helm_version) < LooseVersion("3.7.0"):
opt_result["warnings"] = []
opt_result["warnings"].append(
"helm uninstall support option --wait for helm release >= 3.7.0"
)
wait = False

helm_cmd = delete(
helm_cmd, release_name, purge, disable_hook, wait, wait_timeout
)
changed = True
helm_cmd = delete(
helm_cmd, release_name, purge, disable_hook, wait, wait_timeout
)
changed = True
elif release_state == "present":

if chart_version is not None:
helm_cmd += " --version=" + chart_version

Expand Down Expand Up @@ -956,7 +964,7 @@ def main():
changed=changed,
stdout=out,
stderr=err,
status=get_release_status(module, release_name),
status=get_release_status(module, release_name, all_status=True),
command=helm_cmd,
**opt_result,
)
Expand Down
129 changes: 129 additions & 0 deletions tests/integration/targets/helm/library/helm_test_pending.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: (c) 2023, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function

__metaclass__ = type


DOCUMENTATION = r"""
---
module: helm_test_pending
short_description: created pending-install release
author:
- Aubin Bikouo (@abikouo)
requirements:
- "helm (https://github.com/helm/helm/releases)"
description:
- This module is used to create a pending install release for integration testing
- The scope of this module is the integration testing of the kubernetes.core collection only.
options:
binary_path:
description:
- The path of a helm binary to use.
required: true
type: path
chart_ref:
description:
- chart reference on chart repository (e.g. my-repo/my-chart-ref)
required: true
type: str
chart_release:
description:
- Release name to manage.
required: true
type: str
chart_release_namespace:
description:
- Kubernetes namespace where the chart should be installed.
required: true
type: str
"""

EXAMPLES = r"""
"""

RETURN = r"""
"""

import subprocess
import json
import time
from ansible.module_utils.basic import AnsibleModule


class HelmReleaseNotFoundError(Exception):
def __init__(self, message):
super().__init__(message)


def create_pending_install_release(helm_binary, chart_ref, chart_release, namespace):
# create pending-install release
command = [
helm_binary,
"install",
chart_release,
chart_ref,
"--namespace",
namespace,
"--wait",
]
proc = subprocess.Popen(command)
time.sleep(2)
proc.kill()
# ensure release status is pending-install
command = [
helm_binary,
"list",
"--all",
"--output=json",
"--namespace",
namespace,
"--filter",
chart_release,
]
cmd = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = cmd.communicate()

data = json.loads(out)
if not data:
error = "Release %s not found." % chart_release
raise HelmReleaseNotFoundError(message=error)
return data[0]["status"] == "pending-install", data[0]["status"]


def main():
module = AnsibleModule(
argument_spec=dict(
binary_path=dict(type="path", required=True),
chart_ref=dict(type="str", required=True),
chart_release=dict(type="str", required=True),
chart_release_namespace=dict(type="str", required=True),
),
)

params = dict(
helm_binary=module.params.get("binary_path"),
chart_release=module.params.get("chart_release"),
chart_ref=module.params.get("chart_ref"),
namespace=module.params.get("chart_release_namespace"),
)

try:
result, status = create_pending_install_release(**params)
if not result:
module.fail_json(
msg="unable to create pending-install release, current status is %s"
% status
)
module.exit_json(changed=True, msg="Release created with status '%s'" % status)
except HelmReleaseNotFoundError as err:
module.fail_json(
msg="Error while trying to create pending-install release due to '%s'" % err
)


if __name__ == "__main__":
main()
31 changes: 31 additions & 0 deletions tests/integration/targets/helm/tasks/test_helm_uninstall.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- vars:
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"
chart_name: "test-wait-uninstall"
chart_name_pending: "test-uninstall-pending-release"
helm_namespace: "{{ test_namespace[1] }}"
block:

Expand Down Expand Up @@ -64,6 +65,36 @@
wait: yes
register: uninstall

# Test uninstall chart release with 'pending-install' status
- name: Create chart release with 'pending-install' status
helm_test_pending:
binary_path: "{{ helm_binary }}"
chart_ref: "{{ chart_source }}"
chart_release: "{{ chart_name_pending }}"
chart_release_namespace: "{{ helm_namespace }}"

- name: Uninstall chart release with 'pending-install' status
helm:
binary_path: "{{ helm_binary }}"
release_name: "{{ chart_name_pending }}"
namespace: "{{ helm_namespace }}"
release_state: absent
register: _uninstall

- name: Get Helm release details
helm_info:
binary_path: "{{ helm_binary }}"
release_namespace: "{{ helm_namespace }}"
release_state: pending
release_name: "{{ chart_name_pending }}"
register: _info

- name: assert release does not exist anymore
assert:
that:
- _uninstall is changed
- _info.status is undefined

always:
- name: Delete temp directory
file:
Expand Down

0 comments on commit 09a3c83

Please sign in to comment.