-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add tutorial for external plugin
- Loading branch information
Showing
1 changed file
with
155 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
# Extending Kubebuilder with external plugins | ||
|
||
## Overview | ||
|
||
You can extend the Kubebuilder functionality by introducing external plugin. | ||
|
||
An external plugin is an executable that provides the same kubebuilder plugin features. Since it is an executable, such customized plugin can be implemented in any language. | ||
|
||
The Kubebuilder CLI loads the external plugin in the specified path and interact the plugin through the executable's `stdin` & `stdout`. | ||
|
||
## When is it useful? | ||
|
||
- If you want to create helpers or addons on top of the scaffolds done by the Kubebuilder internal plugins. | ||
|
||
- If you design customized layouts and want to take advantage of functions from Kubebuilder library. | ||
|
||
- If you are looking for implementing plugins by a different language other than `Go`. | ||
|
||
## How to write it? | ||
|
||
The inter-process communication between your external plugin and Kubebuilder is through the standard I/O. | ||
|
||
You can write your external plugin in any language as long as it implements the `PluginRequest` and `PluginResponse` interfaces. | ||
|
||
`PluginRequest` holds all the information Kubebuilder receives from the CLI and the plugins that were executed before it. | ||
The marshaled `PluginRequest` (which should be a `JSON` object) would be sent over `stdin` to the external plugin by Kubebuilder. | ||
|
||
```go | ||
// PluginRequest contains all information kubebuilder received from the CLI | ||
// and plugins executed before it. | ||
type PluginRequest struct { | ||
// APIVersion defines the versioned schema of PluginRequest that is being sent from Kubebuilder. | ||
// Initially, this will be marked as alpha (v1alpha1). | ||
APIVersion string `json:"apiVersion"` | ||
|
||
// Args holds the plugin specific arguments that are received from the CLI | ||
// which are to be passed down to the external plugin. | ||
Args []string `json:"args"` | ||
|
||
// Command contains the command to be executed by the plugin such as init, create api, etc. | ||
Command string `json:"command"` | ||
|
||
// Universe represents the modified file contents that gets updated over a series of plugin runs | ||
// across the plugin chain. Initially, it starts out as empty. | ||
Universe map[string]string `json:"universe"` | ||
} | ||
``` | ||
|
||
`PluginResponse` is what the plugin constructs with the updated universe and serialized and sent back to Kubebuilder through `stdout`. | ||
|
||
```go | ||
// PluginResponse is returned to kubebuilder by the plugin and contains all files | ||
// written by the plugin following a certain command. | ||
type PluginResponse struct { | ||
// APIVersion defines the versioned schema of the PluginResponse that is back sent back to Kubebuilder. | ||
// Initially, this will be marked as alpha (v1alpha1) | ||
APIVersion string `json:"apiVersion"` | ||
|
||
// Command holds the command that gets executed by the plugin such as init, create api, etc. | ||
Command string `json:"command"` | ||
|
||
// Metadata contains the plugin specific help text that the plugin returns to Kubebuilder when it receives | ||
// `--help` flag from Kubebuilder. | ||
Metadata plugin.SubcommandMetadata `json:"metadata"` | ||
|
||
// Universe in the PluginResponse represents the updated file contents that was written by the plugin. | ||
Universe map[string]string `json:"universe"` | ||
|
||
// Error is a boolean type that indicates whether there were any errors due to plugin failures. | ||
Error bool `json:"error,omitempty"` | ||
|
||
// ErrorMsgs contains the specific error messages of the plugin failures. | ||
ErrorMsgs []string `json:"errorMsgs,omitempty"` | ||
|
||
// Flags contains the plugin specific flags that the plugin returns to Kubebuilder when it receives | ||
// a request for a list of supported flags from Kubebuilder | ||
Flags []Flag `json:"flags,omitempty"` | ||
} | ||
``` | ||
|
||
<aside class="note"> | ||
<h1>Caution</h1> | ||
|
||
When writing your own external plugin, you **should not** directly echo or print anything to the stdout. | ||
|
||
This is because Kubebuilder and your plugin are communicating with each other via `stdin` and `stdout` using structured `JSON` data. | ||
Any additional information sent to stdout (such as debug messages or logs) that's not part of the expected PluginResponse JSON structure may cause parsing errors when Kubebuilder tries to read and decode the response from your plugin. | ||
|
||
If you need to include logs or debug messages while developing your plugin, consider writing these messages to a log file instead. | ||
|
||
</aside> | ||
|
||
## How to use it? | ||
|
||
### Prerequisites | ||
|
||
- You have built and installed your Kubebuilder binary. | ||
|
||
- You have built and installed your external plugin as an **executable / binary**. | ||
|
||
- Your plugin is put in a path following the GVK schema: | ||
```sh | ||
/path1/path2/${name}/${version} | ||
``` | ||
|
||
### Usage: | ||
|
||
The external plugin supports the same subcommands as kubebuilder already provides: | ||
- `init`: project initialization. | ||
- `create api`: scaffold Kubernetes API definitions. | ||
- `create webhook`: scaffold Kubernetes webhooks. | ||
|
||
|
||
Also, if the plugin is put in a configured path, you need to use a env variable `$EXTERNAL_PLUGINS_PATH` to tell Kubebuilder where to search for the plugin binary. | ||
|
||
Otherwise, Kubebuilder would search for the plugins in a default path based on your OS: | ||
1. On Linux: | ||
```sh | ||
$XDG_CONFIG_HOME/kubebuilder/plugins/${name}/${version} | ||
``` | ||
|
||
2. On OSX | ||
```sh | ||
~/Library/Application Support/kubebuilder/plugins/${name}/${version} | ||
``` | ||
|
||
**Examples** | ||
```sh | ||
# Initialize a new project with the external plugin named `sampleplugin` | ||
EXTERNAL_PLUGINS_PATH=/path1/path2/sampleplugin/v1/sampleplugin kubebuilder init --plugins sampleplugin/v1 | ||
|
||
# Create a new API with the above external plugin with a customized flag `number` | ||
EXTERNAL_PLUGINS_PATH=/path1/path2/sampleplugin/v1/sampleplugin kubebuilder create api --plugins sampleplugin/v1 --number 2 | ||
|
||
# Create a webhook with the above external plugin with a customized flag `hooked` | ||
EXTERNAL_PLUGINS_PATH=/path1/path2/sampleplugin/v1/sampleplugin kubebuilder create webhook --plugins sampleplugin/v1 --hooked | ||
|
||
# Display help information of the `create api` subcommand of the external plugin | ||
EXTERNAL_PLUGINS_PATH=/path1/path2/sampleplugin/v1/sampleplugin kubebuilder create api --plugins sampleplugin/v1 --help | ||
|
||
# Create new APIs with external plugins v1 and v2 by respecting the plugin chaining order | ||
EXTERNAL_PLUGINS_PATH=/path1/path2/sampleplugin/v1/sampleplugin kubebuilder create api --plugins sampleplugin/v1,sampleplugin/v2 | ||
|
||
# Create new APIs with the go/v4 plugin and then pass those files to the external plugin by respecting the plugin chaining order | ||
EXTERNAL_PLUGINS_PATH=/path1/path2/sampleplugin/v1/sampleplugin kubebuilder create api --plugins go/v4,sampleplugin/v1 | ||
``` | ||
|
||
|
||
## Further resources | ||
|
||
- Check the [design proposal of the external plugin](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-2.md) | ||
- Check the [plugin implementation](https://github.com/kubernetes-sigs/kubebuilder/pull/2338) | ||
- A [sample external plugin written in Go](https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/simple-external-plugin-tutorial/testdata/sampleexternalplugin/v1) | ||
- A [sample external plugin written in Python](https://github.com/rashmigottipati/POC-Phase2-Plugins) | ||
- A [sample external plugin written in JavaScript](https://github.com/Eileen-Yu/kb-js-plugin) |