6cb70e7eb3
Various typo fixes in documents Various grammar and language changes for clarification Change-Id: I111bf45c90405a26d09a5254733a055c78b47407
235 lines
6.6 KiB
Markdown
235 lines
6.6 KiB
Markdown
# Plugin Support
|
|
|
|
## Table of Contents
|
|
|
|
* [Compile-In Plugins](#compile-in-plugins)
|
|
* [Fine Tuning a Build](#fine-tuning-a-build)
|
|
* [Command Selection](#command-selection)
|
|
* [Accessing `airshipctl` settings](#accessing-airshipctl-settings)
|
|
|
|
Our requirements for `airshipctl` contain two very conflicting concepts. One,
|
|
we'd like to assert that `airshipctl` is a statically linked executable, such
|
|
that it can be easily distributed. Two, we'd like to have plugin support. These
|
|
requirements can't coincide within the same project under the standard
|
|
definition of a plugin. Our solution is to provide a more refined definition of
|
|
what a plugin actually is.
|
|
|
|
## Compile-In Plugins
|
|
|
|
In order to support plugins to an independent binary file, we use the concept
|
|
of "compile-in plugins". A "compile-in plugin" is an add-on that is built into
|
|
the main application at compile time, as opposed to runtime. This means that
|
|
while `airshipctl` is a standalone application, it also acts as a sort of
|
|
library. In fact, taking a deeper look at `airshipctl` reveals that the base
|
|
application is incredibly simple. At its core, `airshipctl` provides exactly 2
|
|
commands: `version` and `help`. Take a look at the following snippet to see
|
|
what this looks like:
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"opendev.org/airship/airshipctl/cmd"
|
|
)
|
|
|
|
func main() {
|
|
rootCmd, _, err := cmd.NewRootCmd(os.Stdout)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
rootCmd.Execute()
|
|
}
|
|
```
|
|
|
|
Compiling and running the above gives the following output:
|
|
|
|
```
|
|
$ ./airshipctl
|
|
airshipctl is a unified entrypoint to various airship components
|
|
|
|
Usage:
|
|
airshipctl [command]
|
|
|
|
Available Commands:
|
|
bootstrap Bootstrap ephemeral Kubernetes cluster
|
|
completion Generate autocompletions script for the specified shell (bash or zsh)
|
|
config Modify airshipctl config files
|
|
document manages deployment documents
|
|
help Help about any command
|
|
kubectl kubectl controls the Kubernetes cluster manager
|
|
version Show the version number of airshipctl
|
|
|
|
Flags:
|
|
--airshipconf string Path to file for airshipctl configuration. (default "$HOME/.airship/config")
|
|
--debug enable verbose output
|
|
-h, --help help for airshipctl
|
|
--kubeconfig string Path to kubeconfig associated with airshipctl configuration. (default "$HOME/.airship/kubeconfig")
|
|
|
|
Additional help topics:
|
|
airshipctl cluster Control Kubernetes cluster
|
|
|
|
Use "airshipctl [command] --help" for more information about a command.
|
|
```
|
|
|
|
Every other command is treated as a plugin. Changing `main` to the following
|
|
adds the default commands, or "plugins", to the `airshipctl` tool:
|
|
|
|
```go
|
|
func main() {
|
|
rootCmd, settings, err := cmd.NewRootCmd(os.Stdout)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
cmd.AddDefaultAirshipCTLCommands(rootCmd, settings)
|
|
rootCmd.Execute()
|
|
}
|
|
```
|
|
|
|
Compiling and running now provides the following commands:
|
|
|
|
```
|
|
Available Commands:
|
|
bootstrap Bootstrap ephemeral Kubernetes cluster
|
|
completion Generate autocompletions script for the specified shell (bash or zsh)
|
|
config Modify airshipctl config files
|
|
document manages deployment documents
|
|
help Help about any command
|
|
kubectl kubectl controls the Kubernetes cluster manager
|
|
version Show the version number of airshipctl
|
|
------ more commands TBD ------
|
|
```
|
|
|
|
Downloading and building the main `airshipctl` project will default to
|
|
providing the builtin commands (such as `bootstrap`), much like the above. A
|
|
plugin author wishing to use `airshipctl` can then use the `rootCmd` as the
|
|
first of a series of building blocks. The following demonstrates the addition
|
|
of a new command, `hello`:
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"opendev.org/airship/airshipctl/cmd"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func main() {
|
|
rootCmd, settings, err := cmd.NewRootCmd(os.Stdout)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
cmd.AddDefaultAirshipCTLCommands(rootCmd, settings)
|
|
|
|
helloCmd := &cobra.Command{
|
|
Use: "hello",
|
|
Short: "Prints a friendly message to the screen",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
fmt.Println("Hello World!")
|
|
},
|
|
}
|
|
rootCmd.AddCommand(helloCmd)
|
|
|
|
rootCmd.Execute()
|
|
}
|
|
```
|
|
|
|
## Fine Tuning a Build
|
|
|
|
There are a couple of ways in which a plugin author can fine tune their version
|
|
of `airshipctl`. These manifest as an ability to pick and choose various
|
|
plugins (including the defaults), and capabilities for accessing the same
|
|
settings as other `airshipctl` commands.
|
|
|
|
### Command Selection
|
|
|
|
In the previous section, we introduced the `AddDefaultAirshipCTLCommands`
|
|
function. That command will simply dump all of the builtin commands onto the
|
|
root. But a plugin author might not need all of the builtins. To deal with
|
|
this, the author can pick and choose specific commands to add to their
|
|
`airshipctl`, much like the following:
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"opendev.org/airship/airshipctl/cmd"
|
|
"opendev.org/airship/airshipctl/cmd/bootstrap"
|
|
)
|
|
|
|
func main() {
|
|
rootCmd, settings, err := cmd.NewRootCmd(os.Stdout)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
rootCmd.AddCommand(bootstrap.NewBootstrapCommand(settings))
|
|
rootCmd.Execute()
|
|
}
|
|
```
|
|
|
|
This variant of `airshipctl` will have the `bootstrap` command, but will not
|
|
have any other builtins.
|
|
|
|
This can be particularly useful if a plugin author desires to "override" a
|
|
specific functionality provided by a builtin command. For example, you might
|
|
write your own `bootstrap` command and use it in place of the builtin.
|
|
|
|
### Accessing `airshipctl` settings
|
|
|
|
The `airshipctl` will contain several settings which may be useful to a plugin
|
|
author. The following snippet demonstrates how to use the `debug` flag,
|
|
provided by `airshipctl`, as well as a custom `alt-message` flag, provided by
|
|
the plugin.
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"opendev.org/airship/airshipctl/cmd"
|
|
"opendev.org/airship/airshipctl/pkg/environment"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type Settings struct {
|
|
*environment.AirshipCTLSettings
|
|
|
|
AltMessage bool
|
|
}
|
|
|
|
func main() {
|
|
rootCmd, rootSettings, err := cmd.NewRootCmd(os.Stdout)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
settings := Settings{AirshipCTLSettings: rootSettings}
|
|
helloCmd := &cobra.Command{
|
|
Use: "hello",
|
|
Short: "Prints a friendly message to the screen",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
if settings.Debug {
|
|
fmt.Println("DEBUG: a debugging message")
|
|
}
|
|
if settings.AltMessage {
|
|
fmt.Println("Goodbye World!")
|
|
} else {
|
|
fmt.Println("Hello World!")
|
|
}
|
|
},
|
|
}
|
|
helloCmd.PersistentFlags().BoolVar(&settings.AltMessage, "alt-message", false, "display an alternate message")
|
|
rootCmd.AddCommand(helloCmd)
|
|
|
|
rootCmd.Execute()
|
|
}
|
|
```
|
|
|
|
The `AirshipCTLSettings` object can be found
|
|
[here](../../pkg/environment/settings.go). Future documentation TBD.
|