Chapter 7. Extending the CLI
7.1. 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. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend to use them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
See the Red Hat Technology Preview features support scope for more information.
7.2. Prerequisites
You must have:
-
A working
oc
binary installed. -
An
oc
version of 3.7 or later (recommended).
7.3. 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 Container Platform 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.
7.3.1. 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.
7.3.1.1. 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. TheKUBECTL_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.${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 theXDG_DATA_DIRS
environment variable. IfXDG_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:# Loads plugins from both /path/to/dir1 and /path/to/dir2 $ KUBECTL_PLUGINS_PATH=/path/to/dir1:/path/to/dir2 kubectl plugin -h
7.4. 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.
7.4.1. 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.
7.4.2. 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
7.4.3. 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 theoc
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 invokeoc
and obtain the information you need, using for exampleoc 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 byoc
. 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 precedinggreat-plugin
example.