From 8983a03ca09ea3a0978ca88213ae6d16a0c5857c Mon Sep 17 00:00:00 2001 From: Eileen Date: Thu, 6 Jul 2023 19:14:44 -0400 Subject: [PATCH] docs: add tutorial for external plugin --- docs/book/src/plugins/external-plugins.md | 155 ++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/book/src/plugins/external-plugins.md diff --git a/docs/book/src/plugins/external-plugins.md b/docs/book/src/plugins/external-plugins.md new file mode 100644 index 00000000000..79aee5439c4 --- /dev/null +++ b/docs/book/src/plugins/external-plugins.md @@ -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"` +} +``` + + + +## 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)