Cloud Foundry Internals: How to Create Custom BOSH CLI Plugins
An ability to easily extend core functionality is a key for any system’s evolution. Every popular config management or cloud orchestration tool offers a handy and effective way to do so. For instance, knife plugins in Chef, custom functions in Puppet, and terraform plugins. Being a complex tool, BOSH also provides out-of-the-box utilities for the purpose. The best option for extending BOSH functionality are plugins for a command-line interface (CLI). In fact, major part of the BOSH command-line utilities are implemented as BOSH plugins: the standard BOSH commands, MicroBOSH, BOSH AWS plugin, etc.
Unfortunately, there is no official documentation available on how to create a custom BOSH plugin by yourself, so I decided to compile such a tutorial.
Where to start?
Creating custom plugins for BOSH CLI is pretty easy. Usually, a plugin is a gem with specific class structure. To skip the first steps and avoid creating the whole file structure manually, we wrote the BOSH CLI plugin to generate a simple plugin for you. You are welcome to take advantage of it.
Plugin structure
There is no specific naming conventions for BOSH plugins. The main BOSH repository has plugin names built in the following way: bosh_cli_plugin_<plugin-name>. Still, you are not forced to do it.
Let’s imagine we want to create a BOSH plugin to perform some “magic” action. The best gem name for this case I came to was “bosh-magic.” This gem is expected to have a special folder structure:
The ./lib/bosh/cli/commands/magic.rb file is expected to declare the Bosh::Cli::Command::Magic class that is inherited from Bosh::Cli::Command::Base. BOSH has a discovery mechanism that loads such classes every time the bosh binary is executed. You can set up instance methods from Bosh::Cli::Command::Magic to be called, when specific command line parameters are passed to the bosh binary.
DSL to create a BOSH command
To create a BOSH CLI plugin, you can take advantage of a simple DSL (domain specific language) that goes with the bosh_cli module. The sample below declares a method that will be called after executing the following command:
bosh say hello “John Doe”
The main keyword for this case is “usage.” The “usage” method describes the way BOSH expects the command to be used. The method that follows this declaration is going to be invoked after a specified command is passed to BOSH. It is a mandatory keyword to create a new command for BOSH. If you try to register an already existing command, BOSH will raise exception. To avoid collision between BOSH commands, it is recommended to use a namespace with a plugin name before your commands.
The next keyword is “desc.” It sets a text that will be shown as a help notice. A help message will contain data gathered from the “option” field, too. The “option” adds a possible option to your command. The first argument shows how this option can be used. It is parsed with Ruby OptionParser and it means you can use all it’s features.
If it has no separators (space or equals sign), it is treated as a boolean flag. Options that have value are passed in the following way: “–switch=MANDATORY” or “–switch MANDATORY.” If you need to make your parameter optional, put bracket braces around value as it is done here: “–switch[=OPTIONAL].” The last argument of the “option” method is a string that appears in a help notice. After the options are parsed, they are stored in the options hash.
Examples
You can find plenty of examples in the BOSH repository, such as implementations of MicroBOSH or other commands. This example also uses the BOSH output extension. There are a lot of useful methods for output in the core ext: say, with_indent, header, nl, err, quit, pretty_size, format_time, make_green, etc.
Surely, there is nothing better than a good example to learn (except for two good examples):
MicroBOSH, implemented as a BOSH plugin
bosh-workspaces, a plugin for creating reproducible and upgradable deployments
bosh-plugin-generator, a simple BOSH plugin to generate other BOSH plugins
The third plugin on the list, bosh-plugin-generator, was built by us to simplify BOSH CLI plugin development. It generates the base structure for the BOSH CLI plugin. You can install it as a gem:
gem install bosh-plugin-generator
After that, you will be able to run “bosh generate plugin example” to generate a simple plugin. Hope, you will find my guidelines helpful to create a new useful plugin. Feel free to ask any questions in comments.