Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helm_remote extension #19

Merged
merged 3 commits into from
Jun 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ All extensions have been vetted and approved by the Tilt team.
- [`conftest`](/conftest): Use [Conftest](https://www.conftest.dev/) to test your configuration files.
- [`docker_build_sub`](/docker_build_sub): Specify extra Dockerfile directives in your Tiltfile beyond [`docker_build`](https://docs.tilt.dev/api.html#api.docker_build).
- [`hello_world`](/hello_world): Print "Hello world!". Used in [Extensions](https://docs.tilt.dev/extensions.html).
- [`helm_remote`](/helm_remote): Install a remote Helm chart (in a way that gets properly uninstalled when running `tilt down`)
- [`jest_test_runner`](/jest_test_runner): Jest JavaScript test runner. Example from [Contribute an Extension](https://docs.tilt.dev/contribute_extension.html).
- [`min_tilt_version`](/min_tilt_version): Require a minimum Tilt version to run this Tiltfile.
- [`namespace`](/namespace): Functions for interacting with namespaces.
Expand Down
42 changes: 42 additions & 0 deletions helm_remote/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Helm Remote
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rendered version of this file can be viewed here


Author: [Bob Jackman](https://github.com/kogi)

Install a remotely hosted Helm chart in a way that it will be properly uninstalled when running `tilt down`

## Usage

Because tilt doesn't have a way to dynamically ignore files, you'll need to add `.helm` to your project's `.tiltignore`
file in order to prevent recursive re-processing of the main Tiltfile when the helm cache changes/updates.

#### Install a Remote Chart

```py
load('ext://helm_remote', 'helm_remote')
helm_remote('myChartName')
```

##### Additional Parameters

```
helm_remote(chart_name, repo_url='', repo_name='', namespace='', version='', username='', password='', values=[], set=[])
```

* `chart_name` ( str ) – the name of the chart to install
* `repo_name` ( str ) – the name of the repo within which to find the chart (assuming the repo is already added locally)
<br> if omitted, defaults to the same value as `chart_name`
* `repo_url` ( str ) – the URL of the repo within which to find the chart (equivalent to `helm repo add <repo_name> <repo_url>`)
* `namespace` ( str ) – the namespace to deploy the chart to (equivalent to helm's `--namespace <namespace> --create-namespace` flags)
* `version` ( str ) – the version of the chart to install. If omitted, defaults to latest version (equivalent to helm's `--version` flag)
* `username` ( str ) – repository authentication username, if needed (equivalent to helm's `--username` flag)
* `password` ( str ) – repository authentication password, if needed (equivalent to helm's `--password` flag)
* `values` ( Union [ str , List [ str ]]) – Specify one or more values files (in addition to the values.yaml file in the chart). Equivalent to the helm's `--values` or `-f` flags
* `set` ( Union [ str , List [ str ]]) – Directly specify one or more values (equivalent to helm's `--set` flag)

#### Change the Cache Location

By default `helm_remote` will store retrieved helm charts in the `.helm` directory at your project's root.
This location can be customized by calling `helm_remote_set_cache_dir(newDirectory)`.
Whether customizing this value or just using the default location, be sure this directory is added to your project's
`.tiltignore` file in order to prevent recursive re-processing of the main Tiltfile when the helm cache changes/updates.
See github [issue #3404](https://github.com/tilt-dev/tilt/issues/3404)
88 changes: 88 additions & 0 deletions helm_remote/Tiltfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@


# this is the root directory into which remote helm charts will be pulled/cloned/untar'd
# use `helm_remote_set_cache_dir(newDir)` to change
# if customizing this location, you will also need to add the new location to your .tiltignore file to prevent infinite loops processing the main tiltfile
helm_remote_cache_dir = './.helm'


def helm_remote_set_cache_dir(directory):
helm_remote_cache_dir = directory


# TODO: =====================================
# if it ever becomes possible for loaded files to also load their own extensions
# this method can be replaced by `load('ext://namespace', 'namespace_create')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def namespace_create(name):
"""Returns YAML for a namespace
Args: name: The namespace name. Currently not validated.
"""
k8s_yaml(blob("""apiVersion: v1
kind: Namespace
metadata:
name: %s
""" % name))
# TODO: end TODO
# =====================================


def helm_remote(chart, repo_url='', repo_name='', values=[], set=[], namespace='', version='', username='', password=''):
# ======== Condition Incoming Arguments
if repo_name == '':
repo_name = chart
if namespace == '':
namespace = 'default'
if repo_url != '':
local('helm repo add %s %s' % (repo_name, repo_url)) # updates if already added

# ======== Create Namespace
if namespace != '' and namespace != 'default':
# avoid a namespace not found error
namespace_create(namespace) # do this early so it manages to register before we attempt to install into it

# ======== Initialize
# -------- targets
pull_target = '%s/%s' % (helm_remote_cache_dir, repo_name)
if version != '':
pull_target += '/%s' % version
else:
pull_target += '/latest'

chart_target = '%s/%s' % (pull_target, chart)

# -------- commands
pull_command = 'helm pull %s/%s --untar --destination %s' % (repo_name, chart, pull_target)
if version != '':
pull_command += ' --version %s' % version
if username != '':
pull_command += ' --username %s' % username
if password != '':
pull_command += ' --password %s' % password

# ======== Perform Installation
local('rm -rf %s' % pull_target)
local(pull_command)
install_crds(chart, chart_target)

# TODO: since neither `k8s_yaml()` nor `helm()` accept resource_deps, sometimes the crds haven't yet finished installing before the below tries to run
if namespace != '':
k8s_yaml(helm(chart_target, name=chart, namespace=namespace, values=values, set=set))
else:
k8s_yaml(helm(chart_target, name=chart, values=values, set=set))


def install_crds(name, directory):
name += '-crds'

files = str(local(r"grep --include '*.yaml' --include '*.yml' -rEil '\bkind\s*:\s+CustomResourceDefinition\s*$' %s | xargs grep -L '^{{-' | head -c -1" % directory))
if (files == '') or (files == '(standard input)'):
files = []
else:
files = files.split("\n")

if len(files) != 0:
local_resource(name+'-install', cmd='kubectl apply -f %s' % " -f ".join(files), deps=files) # we can wait/depend on this, but it won't cause a proper uninstall
k8s_yaml(files) # this will cause a proper uninstall, but we can't wait/depend on it

# TODO: Figure out how to avoid another named resource showing up in the tilt HUD for this waiter
local_resource(name+'-ready', resource_deps=[name+'-install'], cmd='kubectl wait --for=condition=Established crd --all') # now we can wait for those crds to finish establishing