blob: eb3285f3850a6981e9dd0fa5b48a9ce2a46bdeb0 [file] [log] [blame]
Giorgi Lekveishvili285ab622023-11-22 13:50:45 +04001# Copyright (C) 2019 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import json
16import subprocess
17
18
19class HelmClient:
20 def __init__(self, kubeconfig, kubecontext):
21 """Wrapper for Helm CLI.
22
23 Arguments:
24 kubeconfig {str} -- Path to kubeconfig-file describing the cluster to
25 connect to.
26 kubecontext {str} -- Name of the context to use.
27 """
28
29 self.kubeconfig = kubeconfig
30 self.kubecontext = kubecontext
31
32 def _exec_command(self, cmd, fail_on_err=True):
33 base_cmd = [
34 "helm",
35 "--kubeconfig",
36 self.kubeconfig,
37 "--kube-context",
38 self.kubecontext,
39 ]
40 return subprocess.run(
41 base_cmd + cmd,
42 stdout=subprocess.PIPE,
43 stderr=subprocess.PIPE,
44 check=fail_on_err,
45 text=True,
46 )
47
48 def install(
49 self,
50 chart,
51 name,
52 values_file=None,
53 set_values=None,
54 namespace=None,
55 fail_on_err=True,
56 wait=True,
57 ):
58 """Installs a chart on the cluster
59
60 Arguments:
61 chart {str} -- Release name or path of a helm chart
62 name {str} -- Name with which the chart will be installed on the cluster
63
64 Keyword Arguments:
65 values_file {str} -- Path to a custom values.yaml file (default: {None})
66 set_values {dict} -- Dictionary containing key-value-pairs that are used
67 to overwrite values in the values.yaml-file.
68 (default: {None})
69 namespace {str} -- Namespace to install the release into (default: {default})
70 fail_on_err {bool} -- Whether to fail with an exception if the installation
71 fails (default: {True})
72 wait {bool} -- Whether to wait for all pods to be ready (default: {True})
73
74 Returns:
75 CompletedProcess -- CompletedProcess-object returned by subprocess
76 containing details about the result and output of the
77 executed command.
78 """
79
80 helm_cmd = ["install", name, chart, "--dependency-update"]
81 if values_file:
82 helm_cmd.extend(("-f", values_file))
83 if set_values:
84 opt_list = [f"{k}={v}" for k, v in set_values.items()]
85 helm_cmd.extend(("--set", ",".join(opt_list)))
86 if namespace:
87 helm_cmd.extend(("--namespace", namespace))
88 if wait:
89 helm_cmd.append("--wait")
90 return self._exec_command(helm_cmd, fail_on_err)
91
92 def list(self, namespace=None):
93 """Lists helm charts installed on the cluster.
94
95 Keyword Arguments:
96 namespace {str} -- Kubernetes namespace (default: {None})
97
98 Returns:
99 list -- List of helm chart realeases installed on the cluster.
100 """
101
102 helm_cmd = ["list", "--all", "--output", "json"]
103 if namespace:
104 helm_cmd.extend(("--namespace", namespace))
105 output = self._exec_command(helm_cmd).stdout
106 return json.loads(output)
107
108 def upgrade(
109 self,
110 chart,
111 name,
112 namespace,
113 values_file=None,
114 set_values=None,
115 reuse_values=True,
116 fail_on_err=True,
117 ):
118 """Updates a chart on the cluster
119
120 Arguments:
121 chart {str} -- Release name or path of a helm chart
122 name {str} -- Name with which the chart will be installed on the cluster
123 namespace {str} -- Kubernetes namespace
124
125 Keyword Arguments:
126 values_file {str} -- Path to a custom values.yaml file (default: {None})
127 set_values {dict} -- Dictionary containing key-value-pairs that are used
128 to overwrite values in the values.yaml-file.
129 (default: {None})
130 reuse_values {bool} -- Whether to reuse existing not overwritten values
131 (default: {True})
132 fail_on_err {bool} -- Whether to fail with an exception if the installation
133 fails (default: {True})
134
135 Returns:
136 CompletedProcess -- CompletedProcess-object returned by subprocess
137 containing details about the result and output of the
138 executed command.
139 """
140 helm_cmd = ["upgrade", name, chart, "--namespace", namespace, "--wait"]
141 if values_file:
142 helm_cmd.extend(("-f", values_file))
143 if reuse_values:
144 helm_cmd.append("--reuse-values")
145 if set_values:
146 opt_list = [f"{k}={v}" for k, v in set_values.items()]
147 helm_cmd.extend(("--set", ",".join(opt_list)))
148 return self._exec_command(helm_cmd, fail_on_err)
149
150 def delete(self, name, namespace=None):
151 """Deletes a chart from the cluster
152
153 Arguments:
154 name {str} -- Name of the chart to delete
155
156 Keyword Arguments:
157 namespace {str} -- Kubernetes namespace (default: {None})
158
159 Returns:
160 CompletedProcess -- CompletedProcess-object returned by subprocess
161 containing details about the result and output of
162 the executed command.
163 """
164
165 if name not in self.list(namespace):
166 return None
167
168 helm_cmd = ["delete", name]
169 if namespace:
170 helm_cmd.extend(("--namespace", namespace))
171 return self._exec_command(helm_cmd)
172
173 def delete_all(self, namespace=None, exceptions=None):
174 """Deletes all charts on the cluster
175
176 Keyword Arguments:
177 namespace {str} -- Kubernetes namespace (default: {None})
178 exceptions {list} -- List of chart names not to delete (default: {None})
179 """
180
181 charts = self.list(namespace)
182 for chart in charts:
183 if exceptions and chart["name"] in exceptions:
184 continue
185 self.delete(chart["name"], namespace)
186
187 def is_installed(self, namespace, chart):
188 """Checks if a chart is installed in the cluster
189
190 Keyword Arguments:
191 namespace {str} -- Kubernetes namespace
192 chart {str} -- Name of the chart
193
194 Returns:
195 bool -- Whether the chart is installed
196 """
197
198 for installed_chart in self.list(namespace):
199 if installed_chart["name"] == chart:
200 return True
201
202 return False