Merge "Handle empty 'helm list' result when there is nothing deployed"
This commit is contained in:
commit
892aafefe5
|
@ -1,6 +1,6 @@
|
|||
# sim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright (c) 2019 Wind River Systems, Inc.
|
||||
# Copyright (c) 2019-2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -25,6 +25,16 @@ import retrying
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO(agrosu):
|
||||
# There is a lot of duplicate code just to execute a helm command
|
||||
# in a subshel.
|
||||
# We should either move to a Helm API or, at least, move all this
|
||||
# suprocess calling and error handling into a common function/object.
|
||||
# python3 supports a 'timeout' parameter for +communicate() which
|
||||
# will raise a subprocess.TimeoutExpired.
|
||||
# When python3 migration is finished, the explicit timer should
|
||||
# be removed.
|
||||
|
||||
def kill_process_and_descendants(proc):
|
||||
# function to kill a process and its children processes
|
||||
for child in psutil.Process(proc.pid).children(recursive=True):
|
||||
|
@ -47,16 +57,7 @@ def refresh_helm_repo_information():
|
|||
rpcapi.refresh_helm_repo_information(context.get_admin_context())
|
||||
|
||||
|
||||
def retrieve_helm_releases():
|
||||
"""Retrieve the deployed helm releases from tiller
|
||||
|
||||
Get the name, namespace and version for the deployed releases
|
||||
by querying helm tiller
|
||||
:return: a dict of deployed helm releases
|
||||
"""
|
||||
deployed_releases = {}
|
||||
|
||||
# Helm v3 releases
|
||||
def retrieve_helm_v3_releases():
|
||||
helm_list = subprocess.Popen(
|
||||
['helm', '--kubeconfig', kubernetes.KUBERNETES_ADMIN_CONF,
|
||||
'list', '--all-namespaces', '--output', 'yaml'],
|
||||
|
@ -64,34 +65,42 @@ def retrieve_helm_releases():
|
|||
timer = threading.Timer(20, kill_process_and_descendants, [helm_list])
|
||||
|
||||
try:
|
||||
releases = {}
|
||||
|
||||
timer.start()
|
||||
out, err = helm_list.communicate()
|
||||
if out and not err:
|
||||
releases = yaml.safe_load(out)
|
||||
elif err and not out:
|
||||
if helm_list.returncode != 0:
|
||||
if err:
|
||||
raise exception.HelmTillerFailure(reason=err)
|
||||
|
||||
# killing the subprocesses with +kill() when timer expires returns EBADF
|
||||
# because the pipe is closed, but no error string on stderr.
|
||||
if helm_list.returncode == -9:
|
||||
raise exception.HelmTillerFailure(
|
||||
reason="helm list operation timed out after "
|
||||
"20 seconds. Terminated by threading timer.")
|
||||
raise exception.HelmTillerFailure(
|
||||
reason="Failed to retrieve releases: %s" % err)
|
||||
elif not err and not out:
|
||||
err_msg = "Failed to retrieve releases. " \
|
||||
"Helm tiller response timeout."
|
||||
raise exception.HelmTillerFailure(reason=err_msg)
|
||||
reason="helm list operation failed without error "
|
||||
"message, errno=%s" % helm_list.returncode)
|
||||
|
||||
for r in releases:
|
||||
r_name = r.get('name')
|
||||
r_version = r.get('revision')
|
||||
r_namespace = r.get('namespace')
|
||||
deployed_releases = {}
|
||||
if out:
|
||||
releases = yaml.safe_load(out)
|
||||
for r in releases:
|
||||
r_name = r.get('name')
|
||||
r_version = r.get('revision')
|
||||
r_namespace = r.get('namespace')
|
||||
|
||||
deployed_releases.setdefault(r_name, {}).update(
|
||||
{r_namespace: r_version})
|
||||
deployed_releases.setdefault(r_name, {}).update(
|
||||
{r_namespace: r_version})
|
||||
|
||||
return deployed_releases
|
||||
except Exception as e:
|
||||
raise exception.HelmTillerFailure(
|
||||
reason="Failed to retrieve releases: %s" % e)
|
||||
reason="Failed to retrieve helmv3 releases: %s" % e)
|
||||
finally:
|
||||
timer.cancel()
|
||||
|
||||
# Helm v2 releases
|
||||
|
||||
def retrieve_helm_v2_releases():
|
||||
env = os.environ.copy()
|
||||
env['PATH'] = '/usr/local/sbin:' + env['PATH']
|
||||
env['KUBECONFIG'] = kubernetes.KUBERNETES_ADMIN_CONF
|
||||
|
@ -103,34 +112,54 @@ def retrieve_helm_releases():
|
|||
timer = threading.Timer(20, kill_process_and_descendants, [helm_list])
|
||||
|
||||
try:
|
||||
releases = {}
|
||||
|
||||
timer.start()
|
||||
out, err = helm_list.communicate()
|
||||
if out and not err:
|
||||
output = yaml.safe_load(out)
|
||||
releases = output.get('Releases', None)
|
||||
elif err and not out:
|
||||
if helm_list.returncode != 0:
|
||||
if err:
|
||||
raise exception.HelmTillerFailure(reason=err)
|
||||
|
||||
# killing the subprocesses with +kill() when timer expires returns EBADF
|
||||
# because the pipe is closed, but no error string on stderr.
|
||||
if helm_list.returncode == -9:
|
||||
raise exception.HelmTillerFailure(
|
||||
reason="helmv2-cli -- helm list operation timed out after "
|
||||
"20 seconds. Terminated by threading timer.")
|
||||
raise exception.HelmTillerFailure(
|
||||
reason="Failed to retrieve releases: %s" % err)
|
||||
elif not err and not out:
|
||||
err_msg = "Failed to retrieve releases. " \
|
||||
"Helm tiller response timeout."
|
||||
raise exception.HelmTillerFailure(reason=err_msg)
|
||||
reason="helmv2-cli -- helm list operation failed without "
|
||||
"error message, errno=%s" % helm_list.returncode)
|
||||
|
||||
for r in releases:
|
||||
r_name = r.get('Name')
|
||||
r_version = r.get('Revision')
|
||||
r_namespace = r.get('Namespace')
|
||||
deployed_releases = {}
|
||||
if out:
|
||||
output = yaml.safe_load(out)
|
||||
releases = output.get('Releases', {})
|
||||
for r in releases:
|
||||
r_name = r.get('Name')
|
||||
r_version = r.get('Revision')
|
||||
r_namespace = r.get('Namespace')
|
||||
|
||||
deployed_releases.setdefault(r_name, {}).update(
|
||||
{r_namespace: r_version})
|
||||
deployed_releases.setdefault(r_name, {}).update(
|
||||
{r_namespace: r_version})
|
||||
|
||||
return deployed_releases
|
||||
except Exception as e:
|
||||
raise exception.HelmTillerFailure(
|
||||
reason="Failed to retrieve releases: %s" % e)
|
||||
reason="Failed to retrieve helmv2 releases: %s" % e)
|
||||
finally:
|
||||
timer.cancel()
|
||||
|
||||
|
||||
def retrieve_helm_releases():
|
||||
"""Retrieve the deployed helm releases from tiller
|
||||
|
||||
Get the name, namespace and version for the deployed releases
|
||||
by querying helm tiller
|
||||
:return: a dict of deployed helm releases
|
||||
"""
|
||||
deployed_releases = {}
|
||||
|
||||
deployed_releases.update(retrieve_helm_v3_releases())
|
||||
deployed_releases.update(retrieve_helm_v2_releases())
|
||||
|
||||
return deployed_releases
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue