# kustomize plugins Quick guides: * [linux exec plugin in 60 sec](execPluginGuidedExample.md) * [linux Go plugin in 60 sec](goPluginGuidedExample.md) Kustomize offers a plugin framework allowing people to write their own resource _generators_ and _transformers_. [generator options]: ../../examples/generatorOptions.md [transformer configs]: ../../examples/transformerconfigs Write a plugin when changing [generator options] or [transformer configs] doesn't meet your needs. [12-factor]: https://12factor.net * A _generator_ plugin could be a helm chart inflator, or a plugin that emits all the components (deployment, service, scaler, ingress, etc.) needed by someone's [12-factor] application, based on a smaller number of free variables. * A _transformer_ plugin might perform special container command line edits, or any other transformation beyond those provided by the builtin (`namePrefix`, `commonLabels`, etc.) transformers. ## Specification in `kustomization.yaml` Start by adding a `generators` and/or `transformers` field to your kustomization. Each field accepts a string list: > ``` > generators: > - relative/path/to/some/file.yaml > - relative/path/to/some/kustomization > - /absolute/path/to/some/kustomization > - https://github.com/org/repo/some/kustomization > > transformers: > - {as above} > ``` The value of each entry in a `generators` or `transformers` list must be a relative path to a YAML file, or a path or URL to a [kustomization]. This is the same format as demanded by the `resources` field. [kustomization]: ../glossary.md#kustomization YAML files are read from disk directly. Paths or URLs leading to kustomizations trigger an in-process kustomization run. Each of the resulting objects is now further interpreted by kustomize as a _plugin configuration_ object. ## Configuration A kustomization file could have the following lines: ``` generators: - chartInflator.yaml ``` Given this, the kustomization process would expect to find a file called `chartInflator.yaml` in the kustomization [root](../glossary.md#kustomization-root). This is the plugin's configuration file; it contains a YAML configuration object. The file `chartInflator.yaml` could contain: ``` apiVersion: someteam.example.com/v1 kind: ChartInflator metadata: name: notImportantHere chartName: minecraft ``` __The `apiVersion` and `kind` fields are used to locate the plugin.__ [k8s object]: ../glossary.md#kubernetes-style-object Thus, these fields are required. They are also required because a kustomize plugin configuration object is also a [k8s object]. To get the plugin ready to generate or transform, it is given the entire contents of the configuration file. [NameTransformer]: ../../plugin/builtin/prefixsuffixtransformer/PrefixSuffixTransformer_test.go [ChartInflator]: ../../plugin/someteam.example.com/v1/chartinflator/ChartInflator_test.go [plugins]: ../../plugin/builtin For more examples of plugin configuration YAML, browse the unit tests below the [plugins] root, e.g. the tests for [ChartInflator] or [NameTransformer]. ## Placement Each plugin gets its own dedicated directory named [`XDG_CONFIG_HOME`]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html ``` $XDG_CONFIG_HOME/kustomize/plugin /${apiVersion}/LOWERCASE(${kind}) ``` The default value of [`XDG_CONFIG_HOME`] is `$HOME/.config`. The one-plugin-per-directory requirement eases creation of a plugin bundle (source, tests, plugin data files, etc.) for sharing. In the case of a [Go plugin](#go-plugins), it also allows one to provide a `go.mod` file for the single plugin, easing resolution of package version dependency skew. When loading, kustomize will first look for an _executable_ file called ``` $XDG_CONFIG_HOME/kustomize/plugin /${apiVersion}/LOWERCASE(${kind})/${kind} ``` If this file is not found or is not executable, kustomize will look for a file called `${kind}.so` in the same directory and attempt to load it as a [Go plugin](#go-plugins). If both checks fail, the plugin load fails the overall `kustomize build`. ## Execution Plugins are only used during a run of the `kustomize build` command. Generator plugins are run after processing the `resources` field (which itself can be viewed as a generator, simply reading objects from disk). The full set of resources is then passed into the transformation pipeline, wherein builtin transformations like `namePrefix` and `commonLabel` are applied (if they were specified in the kustomization file), followed by the user-specified transformers in the `transformers` field. The order specified in the `transformers` field is respected, as transformers cannot be expected to be commutative. #### No Security Kustomize plugins do not run in any kind of kustomize-provided sandbox. There's no notion of _"plugin security"_. A `kustomize build` that tries to use plugins but omits the flag > `--enable_alpha_plugins` will not load plugins and will fail with a warning about plugin use. The use of this flag is an opt-in acknowledging the unstable (alpha) plugin API, the absence of plugin provenance, and the fact that a plugin is not part of kustomize. To be clear, some kustomize plugin downloaded from the internet might wonderfully transform k8s config in a desired manner, while also quietly doing anything the user could do to the system running `kustomize build`. ## Authoring There are two kinds of plugins, [exec](#exec-plugins) and [Go](#go-plugins). ### Exec plugins A _exec plugin_ is any executable that accepts a single argument on its command line - the name of a YAML file containing its configuration (the file name provided in the kustomization file). > TODO: restrictions on plugin to allow the _same exec > plugin_ to be targetted by both the > `generators` and `transformers` fields. > > - first arg could be the fixed string > `generate` or `transform`, > (the name of the configuration file moves to > the 2nd arg), or > - or by default an exec plugin behaves as a tranformer > unless a flag `-g` is provided, switching the > exec plugin to behave as a generator. [helm chart inflator]: ../../plugin/someteam.example.com/v1/chartinflator [bashed config map]: ../../plugin/someteam.example.com/v1/bashedconfigmap [sed transformer]: ../../plugin/someteam.example.com/v1/sedtransformer [hashicorp go-getter]: ../../plugin/someteam.example.com/v1/gogetter #### Examples * [helm chart inflator] - A generator that inflates a helm chart. * [bashed config map] - Super simple configMap generation from bash. * [sed transformer] - Define your unstructured edits using a plugin like this one. * [hashicorp go-getter] - Download kustomize layes and build it to generate resources A generator plugin accepts nothing on `stdin`, but emits generated resources to `stdout`. A transformer plugin accepts resource YAML on `stdin`, and emits those resources, presumably transformed, to `stdout`. kustomize uses an exec plugin adapter to provide marshalled resources on `stdin` and capture `stdout` for further processing. #### Generator Options A generator exec plugin can adjust the generator options for the resources it emits by setting one of the following internal annotations. > NOTE: These annotations are local to kustomize and will not be included in the final output. **`kustomize.config.k8s.io/needs-hash`** Resources can be marked as needing to be processed by the internal hash transformer by including the `needs-hash` annotation. When set valid values for the annotation are `"true"` and `"false"` which respectively enable or disable hash suffixing for the resource. Omitting the annotation is equivalent to setting the value `"false"`. If this annotation is set on a resource not supported by the hash transformer the build will fail. Example: ```yaml apiVersion: v1 kind: ConfigMap metadata: name: cm-test annotations: kustomize.config.k8s.io/needs-hash: "true" data: foo: bar ``` **`kustomize.config.k8s.io/behavior`** The `behavior` annotation will influence how conflicts are handled for resources emitted by the plugin. Valid values include "create", "merge", and "replace" with "create" being the default. Example: ```yaml apiVersion: v1 kind: ConfigMap metadata: name: cm-test annotations: kustomize.config.k8s.io/behavior: "merge" data: foo: bar ``` ### Go plugins Be sure to read [Go plugin caveats](goPluginCaveats.md). [Go plugin]: https://golang.org/pkg/plugin/ A `.go` file can be a [Go plugin] if it declares 'main' as it's package, and exports a symbol to which useful functions are attached. It can further be used as a _kustomize_ plugin if the symbol is named 'KustomizePlugin' and the attached functions implement the `Configurable`, `Generator` and `Transformer` interfaces. A Go plugin for kustomize looks like this: > ``` > package main > > import ( > "sigs.k8s.io/kustomize/api/ifc" > "sigs.k8s.io/kustomize/api/resmap" > ... > ) > > type plugin struct {...} > > var KustomizePlugin plugin > > func (p *plugin) Config( > ldr ifc.Loader, > rf *resmap.Factory, > c []byte) error {...} > > func (p *plugin) Generate() (resmap.ResMap, error) {...} > > func (p *plugin) Transform(m resmap.ResMap) error {...} > ``` Use of the identifiers `plugin`, `KustomizePlugin` and implementation of the method signature `Config` is required. Implementing the `Generator` or `Transformer` method allows (respectively) the plugin's config file to be added to the `generators` or `transformers` field in the kustomization file. Do one or the other or both as desired. [secret generator]: ../../plugin/someteam.example.com/v1/secretsfromdatabase [service generator]: ../../plugin/someteam.example.com/v1/someservicegenerator [string prefixer]: ../../plugin/someteam.example.com/v1/stringprefixer [date prefixer]: ../../plugin/someteam.example.com/v1/dateprefixer [sops encoded secrets]: https://github.com/monopole/sopsencodedsecrets #### Examples * [service generator] - generate a service from a name and port argument. * [string prefixer] - uses the value in `metadata/name` as the prefix. This particular example exists to show how a plugin can transform the behavior of a plugin. See the `TestTransformedTransformers` test in the `target` package. * [date prefixer] - prefix the current date to resource names, a simple example used to modify the string prefixer plugin just mentioned. * [secret generator] - generate secrets from a toy database. * [sops encoded secrets] - a more complex secret generator. * [All the builtin plugins](../../plugin/builtin). User authored plugins are on the same footing as builtin operations. A Go plugin can be both a generator and a transformer. The `Generate` method will run along with all the other generators before the `Transform` method runs. Here's a build command that sensibly assumes the plugin source code sits in the directory where kustomize expects to find `.so` files: ``` d=$XDG_CONFIG_HOME/kustomize/plugin\ /${apiVersion}/LOWERCASE(${kind}) go build -buildmode plugin \ -o $d/${kind}.so $d/${kind}.go ```