import json
import os
import subprocess
from jinja2 import Environment, FileSystemLoader
from k9.core import last_word, namespace_exists, get_default_namespace, create_namespace, run_command
[docs]def helm_repo_add(repo_name: str, repo_url: str):
"""
Adds the repository to the current kubernetes environment.
:param repo_name: Local name of repository
:param repo_url: URL of repository
:return: output string on success, exception if failure.
"""
try:
return run_command('helm', 'repo', 'add', repo_name, repo_url)
except subprocess.CalledProcessError as e:
# ignore error if helm repo already added
if 'already exists' not in str(e.stderr):
raise e
[docs]def helm_repo_update():
"""
Update the local copy of the repository with the current
repository.
:return: output string on success, exception if failure.
"""
return run_command('helm', 'repo', 'update')
[docs]def helm_repo_ls():
"""
Lists available repositories.
:return: Object derived from JSON output, exception on failure.
"""
result = run_command('helm', 'repo', 'list', '-o', 'json')
return json.loads(result.stdout)
[docs]def helm_repo_remove(repo_name: str):
"""
Removes a repository.
:param repo_name:
:return: output string on success, exception if failure.
"""
return run_command('helm', 'repo', 'remove', repo_name)
[docs]def helm_install(chart_name: str, params, release_name: str = None, values_path: str = None,
debug=False, namespace: str = None):
"""
Runs the Helm installation for the specified chart. Before the chart
is installed, the values file which should have the same name as the release_name
will be evaluated with Jinja, using the parameters to build the new values file.
The values file is written to the .output/{{release-name}}-values.yaml.
Helm installation is run with this 'values.yaml' file and on the
default namespace set using set_default_namespace()
:param chart_name: Name of Chart.
:param params: Parameter values in a Dictionary used when pre-processing values. If it is not a dictionary,
the vars() function is run on the object to create a dictionary.
:param release_name: If None - release_name is defaulted to the last word in chart_name. For example
if chart_name is "stable/tomcat", the release_name is "tomcat". Release name
is also used to construct the charts values file in the following format:
./charts/{{release_name}}-values.yaml
:param values_path: Override values file location
:param debug: If True, runs Helm with --debug and --dry-run, which will not actually run
and displays the chart values. Default is False.
:param namespace: Namespace to install the chart on. If None, we use the default namespace.
:return: output string on success, exception if failure.
"""
f = None
try:
if namespace is None:
namespace = get_default_namespace()
if not namespace_exists(namespace):
create_namespace(namespace)
if not isinstance(params, dict):
params = vars(params)
# setup release_name
if release_name is None:
release_name = last_word(chart_name)
# get helm value file
value_fn = f'{release_name}-values.yaml'
vp_dir = './charts/'
if values_path:
vp_dir = values_path[0:values_path.rfind('/')]
if not os.path.exists(f'{vp_dir}/{value_fn}'):
value_fn = f'{release_name}-values.yml'
if not os.path.exists(f'{vp_dir}/{value_fn}'):
print(f'values file not found: {vp_dir}/{value_fn}')
env = Environment(loader=FileSystemLoader(vp_dir), autoescape=True)
template = env.get_template(value_fn)
template_body = template.render(params)
if not os.path.exists('./.output'):
os.mkdir('./.output')
value_path = f'./.output/{value_fn}'
f = open(value_path, 'w+')
f.write(template_body)
f.close()
the_call = ['helm', 'install', '-n', namespace, '-f', value_path, release_name, chart_name]
if debug:
the_call.extend(['--debug', '--dry-run'])
return run_command(*the_call)
finally:
if f is not None:
f.close()
[docs]def helm_ls(namespace: str = None):
"""
Lists all current helm installations.
:param namespace: Namespace to list charts from. If None, we use the default namespace.
:return: List of all helm installations. Throws exception on error.
Sample Output::
[
{"name":"tomcat",
"namespace":"default",
"revision":"1",
"updated":"2019-12-10 18:28:43.753814 -0500 EST",
"status":"deployed",
"chart":"tomcat-0.4.0",
"app_version":"7.0"}
]
"""
if namespace is None:
namespace = get_default_namespace()
result = run_command('helm', '-n', namespace, 'ls', '-o', 'json')
values = json.loads(result.stdout)
return values
[docs]def helm_exists(release_name: str, namespace: str = None):
"""
Returns true if the specified release_name exist.
:param release_name: Name of release.
:param namespace: Namespace to check for the chart in. If None, we use the default namespace.
:return: True if found.
"""
result = helm_ls(namespace)
found = [
release
for release in result
if release['name'] == release_name
]
return len(found) > 0
[docs]def helm_uninstall(release_name: str, namespace: str = None):
"""
Uninstalls the specified release.
:param release_name: Name of the release you want to uninstall.
:param namespace: Namespace to uninstall the chart from. If None, we use the default namespace.
:return: Returns output value from uninstall process. Otherwise, throws exception.
"""
if namespace is None:
namespace = get_default_namespace()
return run_command('helm', 'uninstall', '-n', namespace, release_name)