blob: 1c5eb3fbb274bc8a124626c22ea3c6dcdd03b15a [file] [log] [blame]
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import subprocess
class Helm:
def __init__(self, kubeconfig, kubecontext):
"""Wrapper for Helm CLI.
Arguments:
kubeconfig {str} -- Path to kubeconfig-file describing the cluster to
connect to.
kubecontext {str} -- Name of the context to use.
"""
self.kubeconfig = kubeconfig
self.kubecontext = kubecontext
def _exec_command(self, cmd, fail_on_err=True):
base_cmd = [
"helm",
"--kubeconfig",
self.kubeconfig,
"--kube-context",
self.kubecontext,
]
return subprocess.run(
base_cmd + cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=fail_on_err,
text=True,
)
def init(self, serviceaccount):
"""Installs tiller on the cluster.
Arguments:
serviceaccount {str} -- Name of the service account, which tiller is meant
to use.
Returns:
CompletedProcess -- CompletedProcess-object returned by subprocess
containing details about the result and output of the
executed command.
"""
helm_cmd = ["init", "--wait", "--service-account", serviceaccount]
return self._exec_command(helm_cmd)
def install(
self,
chart,
name,
values_file=None,
set_values=None,
namespace=None,
fail_on_err=True,
):
"""Installs a chart on the cluster
Arguments:
chart {str} -- Release name or path of a helm chart
name {str} -- Name with which the chart will be installed on the cluster
Keyword Arguments:
values_file {str} -- Path to a custom values.yaml file (default: {None})
set_values {dict} -- Dictionary containing key-value-pairs that are used
to overwrite values in the values.yaml-file.
(default: {None})
namespace {str} -- Namespace to install the release into (default: {default})
fail_on_err {bool} -- Whether to fail with an exception if the installation
fails (default: {True})
Returns:
CompletedProcess -- CompletedProcess-object returned by subprocess
containing details about the result and output of the
executed command.
"""
helm_cmd = ["install", chart, "--dep-up", "-n", name, "--wait"]
if values_file:
helm_cmd.extend(("-f", values_file))
if set_values:
opt_list = ["%s=%s" % (k, v) for k, v in set_values.items()]
helm_cmd.extend(("--set", ",".join(opt_list)))
if namespace:
helm_cmd.extend(("--namespace", namespace))
return self._exec_command(helm_cmd, fail_on_err)
def list(self):
"""Lists helm charts installed on the cluster.
Returns:
list -- List of helm chart realeases installed on the cluster.
"""
helm_cmd = ["list", "--all", "--output", "json"]
output = self._exec_command(helm_cmd).stdout
output = json.loads(output)
return output["Releases"]
def upgrade(
self,
chart,
name,
values_file=None,
set_values=None,
reuse_values=True,
recreate_pods=False,
fail_on_err=True,
):
"""Updates a chart on the cluster
Arguments:
chart {str} -- Release name or path of a helm chart
name {str} -- Name with which the chart will be installed on the cluster
Keyword Arguments:
values_file {str} -- Path to a custom values.yaml file (default: {None})
set_values {dict} -- Dictionary containing key-value-pairs that are used
to overwrite values in the values.yaml-file.
(default: {None})
reuse_values {bool} -- Whether to reuse existing not overwritten values
(default: {True})
recreate_pods {bool} -- Whether to restart changed pods (default: {False})
fail_on_err {bool} -- Whether to fail with an exception if the installation
fails (default: {True})
Returns:
CompletedProcess -- CompletedProcess-object returned by subprocess
containing details about the result and output of the
executed command.
"""
helm_cmd = ["upgrade", name, chart, "--wait"]
if values_file:
helm_cmd.extend(("-f", values_file))
if reuse_values:
helm_cmd.append("--reuse-values")
if recreate_pods:
helm_cmd.append("--recreate-pods")
if set_values:
opt_list = ["%s=%s" % (k, v) for k, v in set_values.items()]
helm_cmd.extend(("--set", ",".join(opt_list)))
return self._exec_command(helm_cmd, fail_on_err)
def delete(self, name, purge=True):
"""Deletes a chart from the cluster
Arguments:
name {str} -- Name of the chart to delete
Keyword Arguments:
purge {bool} -- Whether to also remove the release metadata as well
(default: {True})
Returns:
CompletedProcess -- CompletedProcess-object returned by subprocess
containing details about the result and output of the
executed command.
"""
helm_cmd = ["delete", name]
if purge:
helm_cmd.append("--purge")
return self._exec_command(helm_cmd)
def delete_all(self, exceptions=None):
"""Deletes all charts on the cluster
Keyword Arguments:
exceptions {list} -- List of chart names not to delete (default: {None})
"""
charts = self.list()
for chart in charts:
if chart["Name"] in exceptions:
continue
self.delete(chart["Name"])
def reset(self):
"""Uninstall Tiller from cluster
Returns:
CompletedProcess -- CompletedProcess-object returned by subprocess
containing details about the result and output of the
executed command.
"""
helm_cmd = ["reset", "--force"]
return self._exec_command(helm_cmd, fail_on_err=True)