The Helm Plugins Guide (original) (raw)

A Helm plugin is a tool that can be accessed through the helm CLI, but which is not part of the built-in Helm codebase.

Existing plugins can be found onrelated section or by searchingGitHub.

This guide explains how to use and create plugins.

An Overview

Helm plugins are add-on tools that integrate seamlessly with Helm. They provide a way to extend the core feature set of Helm, but without requiring every new feature to be written in Go and added to the core tool.

Helm plugins have the following features:

Helm plugins live in $HELM_PLUGINS. You can find the current value of this, including the default value when not set in the environment, using thehelm env command.

The Helm plugin model is partially based on Git's plugin model. To that end, you may sometimes hear helm referred to as the porcelain layer, with plugins being the plumbing. This is a shorthand way of suggesting that Helm provides the user experience and top level processing logic, while the plugins do the "detail work" of performing a desired action.

Installing a Plugin

Plugins are installed using the $ helm plugin install <path|url> command. You can pass in a path to a plugin on your local file system or a url of a remote VCS repo. The helm plugin install command clones or copies the plugin at the path/url given into $HELM_PLUGINS. If you are installing from a VCS you can specify the version with the --version argument.

$ helm plugin install https://github.com/adamreese/helm-env

If you have a plugin tar distribution, simply untar the plugin into the$HELM_PLUGINS directory. You can also install tarball plugins directly from url by issuing helm plugin install https://domain/path/to/plugin.tar.gz

The Plugin File Structure

In many ways, a plugin is similar to a chart. Each plugin has a top-level directory containing a plugin.yaml file. Additonal files may be present but only the plugin.yaml file is required.

$HELM_PLUGINS/
  |- last/
      |- plugin.yaml

The plugin.yaml File

The plugin.yaml file is required for a plugin. It contains the following fields:

name: The name of the plugin (REQUIRED)
version: A SemVer 2 version (REQUIRED)
usage: Single line usage text shown in help
description: Long description shown in places like helm help
ignoreFlags: Ignore flags passed in from Helm
platformCommand: # Configure command to run based on the platform
  - os: OS match, can be empty or ommited to match all OS'
    arch: Architecture match, can be empty or ommited to match all architectures
    command: Plugin command to execute
    args: Plugin command arguments
command: (DEPRECATED) Plugin command, use platformCommand instead
platformHooks: # Configure plugin lifecycle hooks based on the platform
  install: # Install lifecycle commands
    - os: OS match, can be empty or ommited to match all OS'
      arch: Architecture match, can be empty or ommited to match all architectures
      command: Plugin install command to execute
      args: Plugin install command arguments
  update: # Update lifecycle commands
    - os: OS match, can be empty or ommited to match all OS'
      arch: Architecture match, can be empty or ommited to match all architectures
      command: Plugin update command to execute
      args: Plugin update command arguments
  delete: # Delete lifecycle commands
    - os: OS match, can be empty or ommited to match all OS'
      arch: Architecture match, can be empty or ommited to match all architectures
      command: Plugin delete command to execute
      args: Plugin delete command arguments
hooks: # (Deprecated) Plugin lifecycle hooks, use platformHooks instead
  install: Command to install plugin
  update: Command to update plugin
  delete: Command to delete plugin
downloaders: # Configure downloaders capability
  - command: Command to invoke
    protocols:
      - Protocol schema supported

The name Field

The name is the name of the plugin. When Helm executes this plugin, this is the name it will use (e.g. helm NAME will invoke this plugin).

name should match the directory name. In our example above, that means the plugin with name: last should be contained in a directory named last.

Restrictions on name:

The version Field

The version is the SemVer 2 version of the plugin. usage and description are both used to generate the help text of a command.

The ignoreFlags Field

The ignoreFlags switch tells Helm to not pass flags to the plugin. So if a plugin is called with helm myplugin --foo and ignoreFlags: true, then--foo is silently discarded.

The platformCommand Field

The platformCommand configures the command that the plugin will execute when it is called. You can't set both platformCommand & command as this will result in an error. The following rules will apply in deciding which command to use:

The platformHooks Field

The platformHooks configures the commands that the plugin will execute for lifecycle events. You can't set both platformHooks & hooks as this will resultin an error. The following rules will apply in deciding which hook command to use:

Building a Plugin

Here is the plugin YAML for a simple plugin that helps get the last release name:

name: last
version: 0.1.0
usage: get the last release name
description: get the last release name
ignoreFlags: false
platformCommand:
  - command: ${HELM_BIN}
    args:
      - list
      - --short
      - --max=1
      - --date
      - -r

Plugins may require additional scripts and executables. Scripts can be included in the plugin directory and executables can be downloaded via a hook. The following is an example plugin:

$HELM_PLUGINS/
  |- myplugin/
    |- scripts/
      |- install.ps1
      |- install.sh
    |- plugin.yaml
name: myplugin
version: 0.1.0
usage: example plugin
description: example plugin
ignoreFlags: false
platformCommand:
  - command: ${HELM_PLUGIN_DIR}/bin/myplugin
  - os: windows
    command: ${HELM_PLUGIN_DIR}\bin\myplugin.exe
platformHooks:
  install:
    - command: ${HELM_PLUGIN_DIR}/scripts/install.sh
    - os: windows
      command: pwsh
      args:
        - -c
        - ${HELM_PLUGIN_DIR}\scripts\install.ps1
  update:
    - command: ${HELM_PLUGIN_DIR}/scripts/install.sh
      args:
        - -u
    - os: windows
      command: pwsh
      args:
        - -c
        - ${HELM_PLUGIN_DIR}\scripts\install.ps1
        - -Update

Environment variables are interpolated before the plugin is executed. The pattern above illustrates the preferred way to indicate where the plugin program lives.

Plugin Commands

There are some strategies for working with plugin commands:

Testing a Local Plugin

First you need to find your HELM_PLUGINS path to do it run the folowing command:

Change your current directory to the director that HELM_PLUGINS is set to.

Now you can add a symbolic link to your build output of your plugin in this example we did it for mapkubeapis.

ln -s ~/GitHub/helm-mapkubeapis ./helm-mapkubeapis

Downloader Plugins

By default, Helm is able to pull Charts using HTTP/S. As of Helm 2.4.0, plugins can have a special capability to download Charts from arbitrary sources.

Plugins shall declare this special capability in the plugin.yaml file (top level):

downloaders:
- command: "bin/mydownloader"
  protocols:
  - "myprotocol"
  - "myprotocols"

If such plugin is installed, Helm can interact with the repository using the specified protocol scheme by invoking the command. The special repository shall be added similarly to the regular ones: helm repo add favorite myprotocol://example.com/ The rules for the special repos are the same to the regular ones: Helm must be able to download the index.yaml file in order to discover and cache the list of available Charts.

The defined command will be invoked with the following scheme: command certFile keyFile caFile full-URL. The SSL credentials are coming from the repo definition, stored in $HELM_REPOSITORY_CONFIG(i.e., $HELM_CONFIG_HOME/repositories.yaml). A Downloader plugin is expected to dump the raw content to stdout and report errors on stderr.

The downloader command also supports sub-commands or arguments, allowing you to specify for example bin/mydownloader subcommand -d in the plugin.yaml. This is useful if you want to use the same executable for the main plugin command and the downloader command, but with a different sub-command for each.

Environment Variables

When Helm executes a plugin, it passes the outer environment to the plugin, and also injects some additional environment variables.

Variables like KUBECONFIG are set for the plugin if they are set in the outer environment.

The following variables are guaranteed to be set:

Additionally, if a Kubernetes configuration file was explicitly specified, it will be set as the KUBECONFIG variable

A Note on Flag Parsing

When executing a plugin, Helm will parse global flags for its own use. None of these flags are passed on to the plugin.

Plugins should display help text and then exit for -h and --help. In all other cases, plugins may use flags as appropriate.

Providing shell auto-completion

As of Helm 3.2, a plugin can optionally provide support for shell auto-completion as part of Helm's existing auto-completion mechanism.

Static auto-completion

If a plugin provides its own flags and/or sub-commands, it can inform Helm of them by having a completion.yaml file located in the plugin's root directory. The completion.yaml file has the form:

name: <pluginName>
flags:
- <flag 1>
- <flag 2>
validArgs:
- <arg value 1>
- <arg value 2>
commands:
  name: <commandName>
  flags:
  - <flag 1>
  - <flag 2>
  validArgs:
  - <arg value 1>
  - <arg value 2>
  commands:
     <and so on, recursively>

Notes:

  1. All sections are optional but should be provided if applicable.
  2. Flags should not include the - or -- prefix.
  3. Both short and long flags can and should be specified. A short flag need not be associated with its corresponding long form, but both forms should be listed.
  4. Flags need not be ordered in any way, but need to be listed at the correct point in the sub-command hierarchy of the file.
  5. Helm's existing global flags are already handled by Helm's auto-completion mechanism, therefore plugins need not specify the following flags --debug,--namespace or -n, --kube-context, and --kubeconfig, or any other global flag.
  6. The validArgs list provides a static list of possible completions for the first parameter following a sub-command. It is not always possible to provide such a list in advance (see theDynamic Completion section below), in which case thevalidArgs section can be omitted.

The completion.yaml file is entirely optional. If it is not provided, Helm will simply not provide shell auto-completion for the plugin (unlessDynamic Completion is supported by the plugin). Also, adding acompletion.yaml file is backwards-compatible and will not impact the behavior of the plugin when using older helm versions.

As an example, for thefullstatus plugin which has no sub-commands but accepts the same flags as the helm status command, thecompletion.yaml file is:

name: fullstatus
flags:
- o
- output
- revision

A more intricate example for the2to3 plugin, has a completion.yaml file of:

name: 2to3
commands:
- name: cleanup
  flags:
  - config-cleanup
  - dry-run
  - l
  - label
  - release-cleanup
  - s
  - release-storage
  - tiller-cleanup
  - t
  - tiller-ns
  - tiller-out-cluster
- name: convert
  flags:
  - delete-v2-releases
  - dry-run
  - l
  - label
  - s
  - release-storage
  - release-versions-max
  - t
  - tiller-ns
  - tiller-out-cluster
- name: move
  commands:
  - name: config
    flags:
    - dry-run

Dynamic completion

Also starting with Helm 3.2, plugins can provide their own dynamic shell auto-completion. Dynamic shell auto-completion is the completion of parameter values or flag values that cannot be defined in advance. For example, completion of the names of helm releases currently available on the cluster.

For the plugin to support dynamic auto-completion, it must provide anexecutable file called plugin.complete in its root directory. When the Helm completion script requires dynamic completions for the plugin, it will execute the plugin.complete file, passing it the command-line that needs to be completed. The plugin.complete executable will need to have the logic to determine what the proper completion choices are and output them to standard output to be consumed by the Helm completion script.

The plugin.complete file is entirely optional. If it is not provided, Helm will simply not provide dynamic auto-completion for the plugin. Also, adding aplugin.complete file is backwards-compatible and will not impact the behavior of the plugin when using older helm versions.

The output of the plugin.complete script should be a new-line separated list such as:

When plugin.complete is called, the plugin environment is set just like when the plugin's main script is called. Therefore, the variables $HELM_NAMESPACE,$HELM_KUBECONTEXT, and all other plugin variables will already be set, and their corresponding global flags will be removed.

The plugin.complete file can be in any executable form; it can be a shell script, a Go program, or any other type of program that Helm can execute. Theplugin.complete file must have executable permissions for the user. Theplugin.complete file must exit with a success code (value 0).

In some cases, dynamic completion will require to obtain information from the Kubernetes cluster. For example, the helm fullstatus plugin requires a release name as input. In the fullstatus plugin, for its plugin.completescript to provide completion for current release names, it can simply run helm list -q and output the result.

If it is desired to use the same executable for plugin execution and for plugin completion, the plugin.complete script can be made to call the main plugin executable with some special parameter or flag; when the main plugin executable detects the special parameter or flag, it will know to run the completion. In our example, plugin.complete could be implemented like this:

#!/usr/bin/env sh

# "$@" is the entire command-line that requires completion.
# It is important to double-quote the "$@" variable to preserve a possibly empty last parameter. <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>H</mi><mi>E</mi><mi>L</mi><msub><mi>M</mi><mi>P</mi></msub><mi>L</mi><mi>U</mi><mi>G</mi><mi>I</mi><msub><mi>N</mi><mi>D</mi></msub><mi>I</mi><mi>R</mi><mi mathvariant="normal">/</mi><mi>s</mi><mi>t</mi><mi>a</mi><mi>t</mi><mi>u</mi><mi>s</mi><mi mathvariant="normal">.</mi><mi>s</mi><mi>h</mi><mo>−</mo><mo>−</mo><mi>c</mi><mi>o</mi><mi>m</mi><mi>p</mi><mi>l</mi><mi>e</mi><mi>t</mi><mi>e</mi><mi mathvariant="normal">&quot;</mi></mrow><annotation encoding="application/x-tex">HELM_PLUGIN_DIR/status.sh --complete &quot;</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal">L</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.109em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.10903em;">LU</span><span class="mord mathnormal">G</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.109em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord">/</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">u</span><span class="mord mathnormal">s</span><span class="mord">.</span><span class="mord mathnormal">s</span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord">−</span><span class="mord mathnormal">co</span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.01968em;">pl</span><span class="mord mathnormal">e</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord">&quot;</span></span></span></span>@"

The fullstatus plugin's real script (status.sh) must then look for the--complete flag and if found, printout the proper completions.

Tips and tricks

  1. The shell will automatically filter out completion choices that don't match user input. A plugin can therefore return all relevant completions without removing the ones that don't match the user input. For example, if the command-line is helm fullstatus ngin<TAB>, the plugin.complete script can print all release names (of the default namespace), not just the ones starting with ngin; the shell will only retain the ones starting withngin.
  2. To simplify dynamic completion support, especially if you have a complex plugin, you can have your plugin.complete script call your main plugin script and request completion choices. See theDynamic Completion section above for an example.
  3. To debug dynamic completion and the plugin.complete file, one can run the following to see the completion results :
    • helm __complete <pluginName> <arguments to complete>. For example:
    • helm __complete fullstatus --output js<ENTER>,
    • helm __complete fullstatus -o json ""<ENTER>