Overview

This topic reviews how to install and write extensions for the CLI. Usually called plug-ins or binary extensions, this feature allows you to extend the default set of oc commands available and, therefore, allows you to perform new tasks.

A plug-in is a set of files: typically at least one plugin.yaml descriptor and one or more binary, script, or assets files.

CLI plug-ins are currently only available under the oc plugin subcommand.

CLI plug-ins are currently a Technology Preview feature.

Prerequisites

You must have:

Installing Plug-ins

Copy the plug-in’s plugin.yaml descriptor, binaries, scripts, and assets files to one of the locations in the file system where oc searches for plug-ins.

Currently, OpenShift Origin does not provide a package manager for plug-ins. Therefore, it is your responsibility to place the plug-in files in the correct location. It is recommended that each plug-in is located on its own directory.

To install a plug-in that is distributed as a compressed file, extract it to one of the locations specified in The Plug-in Loader section.

The Plug-in Loader

The plug-in loader is responsible for searching plug-in files, and checking if the plug-in provides the minimum amount of information required for it to run. Files placed in the correct location that do not provide the minimum amount of information (for example, an incomplete plugin.yaml descriptor) are ignored.

Search Order

The plug-in loader uses the following search order:

  1. ${KUBECTL_PLUGINS_PATH}

    If specified, the search stops here.

    If the KUBECTL_PLUGINS_PATH environment variable is present, the loader uses it as the only location to look for plug-ins. The KUBECTL_PLUGINS_PATH environment variable is a list of directories. In Linux and Mac, the list is colon-delimited. In Windows, the list is semicolon-delimited.

    If KUBECTL_PLUGINS_PATH is not present, the loader begins to search the additional locations.

  2. ${XDG_DATA_DIRS}/kubectl/plugins

    The plug-in loader searches one or more directories specified according to the XDG System Directory Structure specification.

    Specifically, the loader locates the directories specified by the XDG_DATA_DIRS environment variable. The plug-in loader searches the kubectl/plugins directory inside of directories specified by the XDG_DATA_DIRS environment variable. If XDG_DATA_DIRS is not specified, it defaults to /usr/local/share:/usr/share.

  3. ~/.kube/plugins

    The plugins directory under the user’s kubeconfig directory. In most cases, this is ~/.kube/plugins:

    # Loads plugins from both /path/to/dir1 and /path/to/dir2
    $ KUBECTL_PLUGINS_PATH=/path/to/dir1:/path/to/dir2 kubectl plugin -h

Writing Plug-ins

You can write a plug-in in any programming language or script that allows you to write CLI commands. A plug-in does not necessarily need to have a binary component. It could rely entirely on operating system utilities like echo, sed, or grep. Alternatively, it could rely on the oc binary.

The only strong requirement for an oc plug-in is the plugin.yaml descriptor file. This file is responsible for declaring at least the minimum attributes required to register a plug-in and must be located under one of the locations specified in the Search Order section.

The plugin.yaml Descriptor

The descriptor file supports the following attributes:

name: "great-plugin"              # REQUIRED: the plug-in command name, to be invoked under 'kubectl'
shortDesc: "great-plugin plug-in" # REQUIRED: the command short description, for help
longDesc: ""                      # the command long description, for help
example: ""                       # command example(s), for help
command: "./example"              # REQUIRED: the command, binary, or script to invoke when running the plug-in
flags:                            # flags supported by the plug-in
  - name: "flag-name"             # REQUIRED for each flag: flag name
    shorthand: "f"                # short version of the flag name
    desc: "example flag"          # REQUIRED for each flag: flag description
    defValue: "extreme"           # default value of the flag
tree:                             # allows the declaration of subcommands
  - ...                           # subcommands support the same set of attributes

The preceding descriptor declares the great-plugin plug-in, which has one flag named -f | --flag-name. It could be invoked as:

$ oc plugin great-plugin -f value

When the plug-in is invoked, it calls the example binary or script, which is located in the same directory as the descriptor file, passing a number of arguments and environment variables. The Accessing Runtime Attributes section describes how the example command accesses the flag value and other runtime context.

Recommended Directory Structure

It is recommended that each plug-in has its own subdirectory in the file system, preferably with the same name as the plug-in command. The directory must contain the plugin.yaml descriptor and any binary, script, asset, or other dependency it might require.

For example, the directory structure for the great-plugin plug-in could look like this:

~/.kube/plugins/
└── great-plugin
    ├── plugin.yaml
    └── example

Accessing Runtime Attributes

In most use cases, the binary or script file you write to support the plug-in must have access to some contextual information provided by the plug-in framework. For example, if you declared flags in the descriptor file, your plug-in must have access to the user-provided flag values at runtime.

The same is true for global flags. The plug-in framework is responsible for doing that, so plug-in writers do not need to worry about parsing arguments. This also ensures the best level of consistency between plug-ins and regular oc commands.

Plug-ins have access to runtime context attributes through environment variables. To access the value provided through a flag, for example, look for the value of the proper environment variable using the appropriate function call for your binary or script.

The supported environment variables are:

  • KUBECTL_PLUGINS_CALLER: The full path to the oc binary that was used in the current command invocation. As a plug-in writer, you do not have to implement logic to authenticate and access the Kubernetes API. Instead, you can use the value provided by this environment variable to invoke oc and obtain the information you need, using for example oc get --raw=/apis.

  • KUBECTL_PLUGINS_CURRENT_NAMESPACE: The current namespace that is the context for this call. This is the actual namespace to be considered in namespaced operations, meaning it was already processed in terms of the precedence between what was provided through the kubeconfig, the --namespace global flag, environment variables, and so on.

  • KUBECTL_PLUGINS_DESCRIPTOR_*: One environment variable for every attribute declared in the plugin.yaml descriptor. For example, KUBECTL_PLUGINS_DESCRIPTOR_NAME, KUBECTL_PLUGINS_DESCRIPTOR_COMMAND.

  • KUBECTL_PLUGINS_GLOBAL_FLAG_*: One environment variable for every global flag supported by oc. For example, KUBECTL_PLUGINS_GLOBAL_FLAG_NAMESPACE, KUBECTL_PLUGINS_GLOBAL_FLAG_LOGLEVEL.

  • KUBECTL_PLUGINS_LOCAL_FLAG_*: One environment variable for every local flag declared in the plugin.yaml descriptor. For example, KUBECTL_PLUGINS_LOCAL_FLAG_HEAT in the preceding great-plugin example.

Plug-in Examples

The OpenShift Origin source contains some plug-in examples.