Extending the CLI

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.

Prerequisites

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, OKD 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:

${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.

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.

~/.kube/plugins

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

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.