parent directory.. | ||||
View all files | ||||
If you have any questions about developing a CLI plugin, ask away on the cf-dev mailing list (many plugin developers there!) or the #cli channel in our Slack community.
Our current plugin architecture currently requires a review and possible large overhaul. Until then, there are no current plans to update our existing architecture. Feel free to provide input here where you can provide feedback.
Go here for documentation of the plugin API
This README discusses how to develop a cf CLI plugin. For user-focused documentation, see Using the cf CLI.
*If you wish to share your plugin with the community, see here for plugin submission.
(Optionally specify --depth 1 to git clone for a faster download without any commit history)
The cf CLI plugin architecture model follows the remote procedure call (RPC) model. The cf CLI invokes each plugin, runs it as an independent executable, and handles all start, stop, and clean up tasks for plugin executable resources.
Here is an illustration of the work flow when a plugin command is being invoked.
1: CLI launches 2 processes, the rpc server and the independent plugin executable
2: Plugin establishes a connection to the RPC server, the connection is used to invoke core cli commands.
3: When a plugin invokes a cli command, it talks to the rpc server, and the rpc server interacts with cf cli to perform the command. The result is passed back to the plugin through the rpc server.
Go here for documentation of the plugin API
To write a plugin for the cf CLI, implement the predefined plugin interface.
The interface uses a Run(...) method as the main entry point between the CLI and a plugin. This method receives the following arguments:
The GetMetadata() function informs the CLI of the name of a plugin, plugin version (optional), minimum CLI version required (optional), the commands it implements, and help text for each command that users can display with cf help.
Plugin names with spaces must be enclosed in quotes when installed and uninstalled (e.g.: cf install-plugin "my plugin"). We recommend that plugin names not contain spaces to prevent the command shell from interpreting the name as multiple words.
To initialize a plugin, call plugin.Start(new(MyPluginStruct)) from within the main() method of your plugin. The plugin.Start(...) function requires a new reference to the struct that implements the defined interface.
This repo contains a basic plugin example here.
To see more examples, go here.
Uninstall of the plugin needs to be explicitly handled. When a user calls the cf uninstall-plugin command, CLI notifies the plugin via a call with CLI-MESSAGE-UNINSTALL as the first item in []args from within the plugin's Run(...) method.
An example which was developed using TDD is available:
The Run(...) method accepts the command line arguments and flags that you define for a plugin.
See the [command line arguments example] (https://github.com/cloudfoundry/cli/blob/main/plugin/plugin_examples/echo/echo.go) included in this repo.
There are several global flags that will not be passed to the plugin. These are:
You can invoke CLI commands with cliConnection.CliCommand([]args) from within a plugin's Run(...) method. The Run(...) method receives the cliConnection as its first argument.
The cliConnection.CliCommand([]args) returns the output printed by the command and an error. The output is returned as a slice of strings. The error will be present if the call to the CLI command fails.
See the test plugin example included in this repo.
Because a plugin has access to stdin during a call to the Run(...) method, you can create interactive plugins. See the interactive plugin example included in this repo.
A single plugin binary can have more than one command, and each command can have it's own help text defined. For an example of multi-command plugins, see the multiple commands example
The recommended approach to debugging plugin code is to print to stdout, or set CF_TRACE to /dev/stderr or a file.
The cf CLI requires an executable file to install the plugin. You must compile the source code with the go build command before distributing the plugin, or instruct your users to compile the plugin source code before installing the plugin. For information about compiling Go source code, see Compile packages and dependencies.
After you compile a plugin, use the following commands to install and manage the plugin.
To install a plugin, run:
cf install-plugin PATH_TO_PLUGIN_BINARY
To display a list of installed plugins and the commands available from each plugin, run:
cf plugins
To remove a plugin, run:
cf uninstall-plugin PLUGIN_NAME
Due to architectural limitations, calling CLI core commands is not concurrency-safe. The correct execution of concurrent commands is not guaranteed. An architecture restructuring is in the works to fix this in the near future.
Due to our legacy code, the plugin architecture does not currently work with newer CLI features. See a more verbose explanation here.
Due to our legacy code, when you CF_TRACE=true, the refresh_token in the request body is not sanitized.