mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-14 02:20:53 +00:00
One plugin per dir.
This commit is contained in:
@@ -1,10 +1,5 @@
|
||||
// +build plugin
|
||||
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/cmd/pluginator
|
||||
package main
|
||||
// Code generated by pluginator on ConfigMapGenerator; DO NOT EDIT.
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -13,16 +8,18 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type plugin struct {
|
||||
type ConfigMapGeneratorPlugin struct {
|
||||
ldr ifc.Loader
|
||||
rf *resmap.Factory
|
||||
types.GeneratorOptions
|
||||
types.ConfigMapArgs
|
||||
}
|
||||
|
||||
var KustomizePlugin plugin
|
||||
func NewConfigMapGeneratorPlugin() *ConfigMapGeneratorPlugin {
|
||||
return &ConfigMapGeneratorPlugin{}
|
||||
}
|
||||
|
||||
func (p *plugin) Config(
|
||||
func (p *ConfigMapGeneratorPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.GeneratorOptions = types.GeneratorOptions{}
|
||||
p.ConfigMapArgs = types.ConfigMapArgs{}
|
||||
@@ -32,7 +29,7 @@ func (p *plugin) Config(
|
||||
return
|
||||
}
|
||||
|
||||
func (p *plugin) Generate() (resmap.ResMap, error) {
|
||||
func (p *ConfigMapGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
argsList := make([]types.ConfigMapArgs, 1)
|
||||
argsList[0] = p.ConfigMapArgs
|
||||
return p.rf.NewResMapFromConfigMapArgs(
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
// +build plugin
|
||||
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/cmd/pluginator
|
||||
package main
|
||||
// Code generated by pluginator on ImageTagTransformer; DO NOT EDIT.
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -17,21 +12,23 @@ import (
|
||||
|
||||
// Find matching image declarations and replace
|
||||
// the name, tag and/or digest.
|
||||
type plugin struct {
|
||||
type ImageTagTransformerPlugin struct {
|
||||
ImageTag image.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
var KustomizePlugin plugin
|
||||
func NewImageTagTransformerPlugin() *ImageTagTransformerPlugin {
|
||||
return &ImageTagTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *plugin) Config(
|
||||
func (p *ImageTagTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.ImageTag = image.Image{}
|
||||
p.FieldSpecs = nil
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||
func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
argsList := make([]image.Image, 1)
|
||||
argsList[0] = p.ImageTag
|
||||
t, err := transformers.NewImageTransformer(argsList, p.FieldSpecs)
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
// +build plugin
|
||||
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/cmd/pluginator
|
||||
package main
|
||||
// Code generated by pluginator on NameTransformer; DO NOT EDIT.
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -15,15 +10,17 @@ import (
|
||||
)
|
||||
|
||||
// Add the given prefix and suffix to the resource name.
|
||||
type plugin struct {
|
||||
type NameTransformerPlugin struct {
|
||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
var KustomizePlugin plugin
|
||||
func NewNameTransformerPlugin() *NameTransformerPlugin {
|
||||
return &NameTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *plugin) Config(
|
||||
func (p *NameTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.Prefix = ""
|
||||
p.Suffix = ""
|
||||
@@ -31,7 +28,7 @@ func (p *plugin) Config(
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||
func (p *NameTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
t, err := transformers.NewNamePrefixSuffixTransformer(
|
||||
p.Prefix,
|
||||
p.Suffix,
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
// +build plugin
|
||||
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/cmd/pluginator
|
||||
package main
|
||||
// Code generated by pluginator on SecretGenerator; DO NOT EDIT.
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -13,16 +8,18 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type plugin struct {
|
||||
type SecretGeneratorPlugin struct {
|
||||
ldr ifc.Loader
|
||||
rf *resmap.Factory
|
||||
types.GeneratorOptions
|
||||
types.SecretArgs
|
||||
}
|
||||
|
||||
var KustomizePlugin plugin
|
||||
func NewSecretGeneratorPlugin() *SecretGeneratorPlugin {
|
||||
return &SecretGeneratorPlugin{}
|
||||
}
|
||||
|
||||
func (p *plugin) Config(
|
||||
func (p *SecretGeneratorPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.GeneratorOptions = types.GeneratorOptions{}
|
||||
p.SecretArgs = types.SecretArgs{}
|
||||
@@ -32,7 +29,7 @@ func (p *plugin) Config(
|
||||
return
|
||||
}
|
||||
|
||||
func (p *plugin) Generate() (resmap.ResMap, error) {
|
||||
func (p *SecretGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
argsList := make([]types.SecretArgs, 1)
|
||||
argsList[0] = p.SecretArgs
|
||||
return p.rf.NewResMapFromSecretArgs(
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// Code generated by pluginator on ConfigMapGenerator; DO NOT EDIT.
|
||||
package builtingen
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/plugin/pluginator
|
||||
package main
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -8,18 +11,16 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type ConfigMapGeneratorPlugin struct {
|
||||
type plugin struct {
|
||||
ldr ifc.Loader
|
||||
rf *resmap.Factory
|
||||
types.GeneratorOptions
|
||||
types.ConfigMapArgs
|
||||
}
|
||||
|
||||
func NewConfigMapGeneratorPlugin() *ConfigMapGeneratorPlugin {
|
||||
return &ConfigMapGeneratorPlugin{}
|
||||
}
|
||||
var KustomizePlugin plugin
|
||||
|
||||
func (p *ConfigMapGeneratorPlugin) Config(
|
||||
func (p *plugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.GeneratorOptions = types.GeneratorOptions{}
|
||||
p.ConfigMapArgs = types.ConfigMapArgs{}
|
||||
@@ -29,7 +30,7 @@ func (p *ConfigMapGeneratorPlugin) Config(
|
||||
return
|
||||
}
|
||||
|
||||
func (p *ConfigMapGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
func (p *plugin) Generate() (resmap.ResMap, error) {
|
||||
argsList := make([]types.ConfigMapArgs, 1)
|
||||
argsList[0] = p.ConfigMapArgs
|
||||
return p.rf.NewResMapFromConfigMapArgs(
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestConfigMapGenerator(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
@@ -1,5 +1,8 @@
|
||||
// Code generated by pluginator on ImageTagTransformer; DO NOT EDIT.
|
||||
package builtingen
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/plugin/pluginator
|
||||
package main
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -12,23 +15,21 @@ import (
|
||||
|
||||
// Find matching image declarations and replace
|
||||
// the name, tag and/or digest.
|
||||
type ImageTagTransformerPlugin struct {
|
||||
type plugin struct {
|
||||
ImageTag image.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
func NewImageTagTransformerPlugin() *ImageTagTransformerPlugin {
|
||||
return &ImageTagTransformerPlugin{}
|
||||
}
|
||||
var KustomizePlugin plugin
|
||||
|
||||
func (p *ImageTagTransformerPlugin) Config(
|
||||
func (p *plugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.ImageTag = image.Image{}
|
||||
p.FieldSpecs = nil
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||
argsList := make([]image.Image, 1)
|
||||
argsList[0] = p.ImageTag
|
||||
t, err := transformers.NewImageTransformer(argsList, p.FieldSpecs)
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestImageTagTransformer(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
@@ -1,5 +1,8 @@
|
||||
// Code generated by pluginator on NameTransformer; DO NOT EDIT.
|
||||
package builtingen
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/plugin/pluginator
|
||||
package main
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -10,17 +13,15 @@ import (
|
||||
)
|
||||
|
||||
// Add the given prefix and suffix to the resource name.
|
||||
type NameTransformerPlugin struct {
|
||||
type plugin struct {
|
||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
func NewNameTransformerPlugin() *NameTransformerPlugin {
|
||||
return &NameTransformerPlugin{}
|
||||
}
|
||||
var KustomizePlugin plugin
|
||||
|
||||
func (p *NameTransformerPlugin) Config(
|
||||
func (p *plugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.Prefix = ""
|
||||
p.Suffix = ""
|
||||
@@ -28,7 +29,7 @@ func (p *NameTransformerPlugin) Config(
|
||||
return yaml.Unmarshal(c, p)
|
||||
}
|
||||
|
||||
func (p *NameTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||
t, err := transformers.NewNamePrefixSuffixTransformer(
|
||||
p.Prefix,
|
||||
p.Suffix,
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNameTransformer(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
@@ -1,5 +1,8 @@
|
||||
// Code generated by pluginator on SecretGenerator; DO NOT EDIT.
|
||||
package builtingen
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/plugin/pluginator
|
||||
package main
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -8,18 +11,16 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type SecretGeneratorPlugin struct {
|
||||
type plugin struct {
|
||||
ldr ifc.Loader
|
||||
rf *resmap.Factory
|
||||
types.GeneratorOptions
|
||||
types.SecretArgs
|
||||
}
|
||||
|
||||
func NewSecretGeneratorPlugin() *SecretGeneratorPlugin {
|
||||
return &SecretGeneratorPlugin{}
|
||||
}
|
||||
var KustomizePlugin plugin
|
||||
|
||||
func (p *SecretGeneratorPlugin) Config(
|
||||
func (p *plugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.GeneratorOptions = types.GeneratorOptions{}
|
||||
p.SecretArgs = types.SecretArgs{}
|
||||
@@ -29,7 +30,7 @@ func (p *SecretGeneratorPlugin) Config(
|
||||
return
|
||||
}
|
||||
|
||||
func (p *SecretGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
func (p *plugin) Generate() (resmap.ResMap, error) {
|
||||
argsList := make([]types.SecretArgs, 1)
|
||||
argsList[0] = p.SecretArgs
|
||||
return p.rf.NewResMapFromSecretArgs(
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestSecretGenerator(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
237
plugin/doc.go
Normal file
237
plugin/doc.go
Normal file
@@ -0,0 +1,237 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*
|
||||
Package plugin contains builtin and example
|
||||
plugins, tests and test libraries, and a code
|
||||
generator for converting a plugin to statically
|
||||
loadable code (see pluginator).
|
||||
|
||||
|
||||
HOW PLUGINS RUN
|
||||
|
||||
Assume a file 'secGen.yaml' containing
|
||||
|
||||
apiVersion: someteam.example.com/v1
|
||||
kind: SecretGenerator
|
||||
metadata:
|
||||
name: makesecrets
|
||||
name: mySecret
|
||||
behavior: merge
|
||||
envs:
|
||||
- db.env
|
||||
- fruit.env
|
||||
|
||||
If this file were referenced by a kustomization
|
||||
file in its 'generators' field, kustomize would
|
||||
|
||||
* Read 'secGen.yaml'.
|
||||
|
||||
* Use the value of $XGD_CONFIG_HOME and
|
||||
'apiversion' and to find an executable
|
||||
named 'SecretGenerator' to use as
|
||||
an exec plugin, or failing that,
|
||||
|
||||
* use the same info to load a Go plugin
|
||||
object file called 'SecretGenerator.so'.
|
||||
|
||||
* Send either the file name 'secGen.yaml' as
|
||||
the first arg to the exec plugin, or send its
|
||||
contents to the go plugin's Config method.
|
||||
|
||||
* Use the plugin to generate and/or transform.
|
||||
|
||||
|
||||
GO PLUGINS
|
||||
|
||||
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 plugin won't load into some program foo/main.go
|
||||
if there is any package version mismatch in the
|
||||
dependencies of the plugin and the dependencies of
|
||||
foo/main.go. Control this with matching
|
||||
declarations in go.mod files. The versions of the
|
||||
builtin packages "fmt", "io", "os" (not normally
|
||||
listed in go.mod) etc have the same version as the
|
||||
compiler.
|
||||
|
||||
|
||||
ONE PLUGIN PER DIRECTORY
|
||||
|
||||
For kustomize (and perhaps anyone), it's simplest
|
||||
to put each plugin into its own directory.
|
||||
|
||||
Go plugins must be in package `main`, and so
|
||||
having more than one plugin in a directory means
|
||||
their loading symbols have to differ, which makes
|
||||
it hard to standardize around how they get loaded,
|
||||
or it means one must use build tags to suppress
|
||||
full directory compilation - which creates
|
||||
difficulties using IDEs, the `go mod` tool, `go
|
||||
test ./...`, etc.
|
||||
|
||||
A one plugin per directory policy makes it easy to
|
||||
define the plugin as a module, with its own
|
||||
`go.mod` file - which is vital for resolving
|
||||
package version dependency mismatches at load
|
||||
time. It also makes it easy to create a plugin
|
||||
tarball (source, test, go.mod, plugin data files,
|
||||
etc.) for distribution.
|
||||
|
||||
|
||||
BUILTIN PLUGIN CONFIGURATION
|
||||
|
||||
For performance reasons, all builting plugins are
|
||||
Go plugins (not exec plugins).
|
||||
|
||||
Using "SecretGenerator" as an example in what
|
||||
follows.
|
||||
|
||||
The plugin config file looks like
|
||||
|
||||
---------------------------------------------
|
||||
apiVersion: builtin
|
||||
kind: SecretGenerator
|
||||
metadata:
|
||||
name: whatever
|
||||
otherField1: whatever
|
||||
otherField2: whatever
|
||||
...
|
||||
---------------------------------------------
|
||||
|
||||
The apiVersion must be 'builtin'. The kind is the
|
||||
CamelCase name of the plugin.
|
||||
|
||||
For non-builtins the apiVersion can be any legal
|
||||
apiVersion value, e.g. 'someteam.example.com/v1beta1'
|
||||
|
||||
The builtin source must be at:
|
||||
|
||||
repo=$GOPATH/src/sigs.k8s.io/kustomize
|
||||
${repo}/plugin/${apiVersion}/LOWERCASE(${kind})/${kind}.go
|
||||
|
||||
(dropping the ".go" for exec plugins).
|
||||
|
||||
k8s wants 'kind' values to follow CamelCase, while
|
||||
Go style doesn't like but does allow such names.
|
||||
|
||||
The lowercased value of kind is used as the name of the
|
||||
directory holding the plugin, its test, and any
|
||||
optional associated files (possibly a go.mod file).
|
||||
|
||||
|
||||
PLUGIN SOURCE
|
||||
|
||||
* Pattern
|
||||
|
||||
secretgenerator.go
|
||||
---------------------------------------------
|
||||
//go:generate go run sigs.k8s.io/kustomize/cmd/pluginator
|
||||
package main
|
||||
import ...
|
||||
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 {...}
|
||||
---------------------------------------------
|
||||
|
||||
The plugin name doesn't appear in the file itself.
|
||||
|
||||
* Compilation
|
||||
|
||||
repo=$GOPATH/src/sigs.k8s.io/kustomize
|
||||
dir=$repo/plugin/builtin
|
||||
go build -buildmode plugin \
|
||||
-o $dir/secretgenerator.so \
|
||||
$dir/secretgenerator.go
|
||||
|
||||
|
||||
|
||||
BUILTIN PLUGIN GENERATION
|
||||
|
||||
The pluginator program is a code generator that
|
||||
converts kustomize generator (G) and/or
|
||||
transformer (T) Go plugins to statically linkable
|
||||
code.
|
||||
|
||||
It arises from following requirements:
|
||||
|
||||
* extension
|
||||
|
||||
kustomize does two things - generate or
|
||||
transform k8s resources. Plugins let
|
||||
users write their own G&T's without
|
||||
having to fork kustomize and learn its
|
||||
internals.
|
||||
|
||||
* dogfooding
|
||||
|
||||
A G&T extension framework one can trust
|
||||
should be used by its authors to deliver
|
||||
builtin G&T's.
|
||||
|
||||
* distribution
|
||||
|
||||
kustomize should be distributable via
|
||||
`go get` and should run where Go
|
||||
programs are expected to run.
|
||||
|
||||
The extension requirement led to the creation
|
||||
of a framework that accommodates writing a
|
||||
G or T as either
|
||||
|
||||
* an 'exec' plugin (any executable file
|
||||
runnable as a kustomize subprocess), or
|
||||
|
||||
* as a Go plugin - see
|
||||
https://golang.org/pkg/plugin.
|
||||
|
||||
The dogfooding (and an implicit performance
|
||||
requirement) requires a 'builtin' G or T to
|
||||
be written as a Go plugin.
|
||||
|
||||
The distribution ('go get') requirement demands
|
||||
conversion of Go plugins to statically linked
|
||||
code, hence this program.
|
||||
|
||||
|
||||
TO GENERATE CODE
|
||||
|
||||
repo=$GOPATH/src/sigs.k8s.io/kustomize
|
||||
cd $repo/plugin/builtin
|
||||
go generate ./...
|
||||
|
||||
This creates
|
||||
|
||||
$repo/plugin/builtin/SecretGenerator.go
|
||||
|
||||
etc.
|
||||
|
||||
Generated plugins are used in kustomize via
|
||||
|
||||
---------------------------------------------
|
||||
package whatever
|
||||
import "sigs.k8s.io/kustomize/plugin/builtin
|
||||
...
|
||||
g := builtin.NewSecretGenerator()
|
||||
g.Config(l, rf, k)
|
||||
resources, err := g.Generate()
|
||||
err = g.Transform(resources)
|
||||
// Eventually emit resources.
|
||||
---------------------------------------------
|
||||
|
||||
*/
|
||||
package plugin
|
||||
@@ -8,15 +8,16 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/pkg/pgmconfig"
|
||||
"sigs.k8s.io/kustomize/pkg/plugins"
|
||||
)
|
||||
|
||||
// PluginTestEnv manages the plugin test environment.
|
||||
// EnvForTest manages the plugin test environment.
|
||||
// It sets/resets XDG_CONFIG_HOME, makes/removes a temp objRoot.
|
||||
type PluginTestEnv struct {
|
||||
type EnvForTest struct {
|
||||
t *testing.T
|
||||
compiler *plugins.Compiler
|
||||
workDir string
|
||||
@@ -24,34 +25,33 @@ type PluginTestEnv struct {
|
||||
wasSet bool
|
||||
}
|
||||
|
||||
func NewPluginTestEnv(t *testing.T) *PluginTestEnv {
|
||||
return &PluginTestEnv{t: t}
|
||||
func NewEnvForTest(t *testing.T) *EnvForTest {
|
||||
return &EnvForTest{t: t}
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) Set() *PluginTestEnv {
|
||||
func (x *EnvForTest) Set() *EnvForTest {
|
||||
x.createWorkDir()
|
||||
x.compiler = x.makeCompiler()
|
||||
x.setEnv()
|
||||
return x
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) Reset() {
|
||||
func (x *EnvForTest) Reset() {
|
||||
x.resetEnv()
|
||||
x.removeWorkDir()
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) BuildGoPlugin(g, v, k string) {
|
||||
func (x *EnvForTest) BuildGoPlugin(g, v, k string) {
|
||||
err := x.compiler.Compile(g, v, k)
|
||||
if err != nil {
|
||||
x.t.Errorf("compile failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) BuildExecPlugin(name ...string) {
|
||||
obj := filepath.Join(
|
||||
append([]string{x.compiler.ObjRoot()}, name...)...)
|
||||
src := filepath.Join(
|
||||
append([]string{x.compiler.SrcRoot()}, name...)...)
|
||||
func (x *EnvForTest) BuildExecPlugin(g, v, k string) {
|
||||
lowK := strings.ToLower(k)
|
||||
obj := filepath.Join(x.compiler.ObjRoot(), g, v, lowK, k)
|
||||
src := filepath.Join(x.compiler.SrcRoot(), g, v, lowK, k)
|
||||
if err := os.MkdirAll(filepath.Dir(obj), 0755); err != nil {
|
||||
x.t.Errorf("error making directory: %s", filepath.Dir(obj))
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func (x *PluginTestEnv) BuildExecPlugin(name ...string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) makeCompiler() *plugins.Compiler {
|
||||
func (x *EnvForTest) makeCompiler() *plugins.Compiler {
|
||||
// The plugin loader wants to find object code under
|
||||
// $XDG_CONFIG_HOME/kustomize/plugins
|
||||
// and the compiler writes object code to
|
||||
@@ -81,7 +81,7 @@ func (x *PluginTestEnv) makeCompiler() *plugins.Compiler {
|
||||
return plugins.NewCompiler(srcRoot, objRoot)
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) createWorkDir() {
|
||||
func (x *EnvForTest) createWorkDir() {
|
||||
var err error
|
||||
x.workDir, err = ioutil.TempDir("", "kustomize-plugin-tests")
|
||||
if err != nil {
|
||||
@@ -89,7 +89,7 @@ func (x *PluginTestEnv) createWorkDir() {
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) removeWorkDir() {
|
||||
func (x *EnvForTest) removeWorkDir() {
|
||||
err := os.RemoveAll(x.workDir)
|
||||
if err != nil {
|
||||
x.t.Errorf(
|
||||
@@ -97,12 +97,12 @@ func (x *PluginTestEnv) removeWorkDir() {
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) setEnv() {
|
||||
func (x *EnvForTest) setEnv() {
|
||||
x.oldXdg, x.wasSet = os.LookupEnv(pgmconfig.XDG_CONFIG_HOME)
|
||||
os.Setenv(pgmconfig.XDG_CONFIG_HOME, x.workDir)
|
||||
}
|
||||
|
||||
func (x *PluginTestEnv) resetEnv() {
|
||||
func (x *EnvForTest) resetEnv() {
|
||||
if x.wasSet {
|
||||
os.Setenv(pgmconfig.XDG_CONFIG_HOME, x.oldXdg)
|
||||
} else {
|
||||
37
plugin/generateBuiltins.sh
Executable file
37
plugin/generateBuiltins.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This script creates the generator and
|
||||
# transformer factory functions in
|
||||
# sigs.k8s.io/kustomize/plugin/builtin
|
||||
# by generating code based on the plugins
|
||||
# found below that directory.
|
||||
|
||||
set -e
|
||||
|
||||
myGoPath=$1
|
||||
if [ -z ${1+x} ]; then
|
||||
myGoPath=$GOPATH
|
||||
fi
|
||||
|
||||
if [ -z "$myGoPath" ]; then
|
||||
echo "Must specify a GOPATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dir=$myGoPath/src/sigs.k8s.io/kustomize
|
||||
|
||||
if [ ! -d "$dir" ]; then
|
||||
echo "$dir is not a directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo Generating linkable plugins...
|
||||
|
||||
pushd $dir >& /dev/null
|
||||
|
||||
GOPATH=$myGoPath go generate \
|
||||
sigs.k8s.io/kustomize/plugin/builtin/...
|
||||
|
||||
popd >& /dev/null
|
||||
|
||||
echo All done.
|
||||
132
plugin/pluginator/main.go
Normal file
132
plugin/pluginator/main.go
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// See plugin/doc.go for an explanation.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/pkg/pgmconfig"
|
||||
"sigs.k8s.io/kustomize/pkg/plugins"
|
||||
)
|
||||
|
||||
func main() {
|
||||
root := inputFileRoot()
|
||||
file, err := os.Open(root + ".go")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
readToPackageMain(scanner, file.Name())
|
||||
|
||||
w := NewWriter(root)
|
||||
defer w.close()
|
||||
|
||||
// This particular phrasing is required.
|
||||
w.write(
|
||||
fmt.Sprintf(
|
||||
"// Code generated by pluginator on %s; DO NOT EDIT.",
|
||||
root))
|
||||
w.write("package builtin")
|
||||
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
if strings.HasPrefix(l, "//go:generate") {
|
||||
continue
|
||||
}
|
||||
if l == "var "+plugins.PluginSymbol+" plugin" {
|
||||
w.write("func New" + root + "Plugin() *" + root + "Plugin {")
|
||||
w.write(" return &" + root + "Plugin{}")
|
||||
w.write("}")
|
||||
continue
|
||||
}
|
||||
w.write(l)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func inputFileRoot() string {
|
||||
n := os.Getenv("GOFILE")
|
||||
if !strings.HasSuffix(n, ".go") {
|
||||
log.Fatalf("expecting .go suffix on %s", n)
|
||||
}
|
||||
return n[:len(n)-len(".go")]
|
||||
}
|
||||
|
||||
func readToPackageMain(s *bufio.Scanner, f string) {
|
||||
gotMain := false
|
||||
for !gotMain && s.Scan() {
|
||||
gotMain = strings.HasPrefix(s.Text(), "package main")
|
||||
}
|
||||
if !gotMain {
|
||||
log.Fatalf("%s missing package main", f)
|
||||
}
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
root string
|
||||
f *os.File
|
||||
}
|
||||
|
||||
func NewWriter(r string) *writer {
|
||||
n := makeOutputFileName(r)
|
||||
f, err := os.Create(n)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create `%s`; %v", n, err)
|
||||
}
|
||||
return &writer{root: r, f: f}
|
||||
}
|
||||
|
||||
func makeOutputFileName(root string) string {
|
||||
return filepath.Join(
|
||||
os.Getenv("GOPATH"),
|
||||
"src",
|
||||
pgmconfig.DomainName,
|
||||
pgmconfig.ProgramName,
|
||||
pgmconfig.PluginRoot,
|
||||
"builtin",
|
||||
root+".go")
|
||||
}
|
||||
|
||||
func (w *writer) close() {
|
||||
fmt.Println("Generated " + w.root)
|
||||
w.f.Close()
|
||||
}
|
||||
|
||||
func (w *writer) write(line string) {
|
||||
_, err := w.f.WriteString(w.filter(line) + "\n")
|
||||
if err != nil {
|
||||
log.Printf("Trouble writing: %s", line)
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) filter(in string) string {
|
||||
if ok, newer := w.replace(in, "type plugin struct"); ok {
|
||||
return newer
|
||||
}
|
||||
if ok, newer := w.replace(in, "*plugin)"); ok {
|
||||
return newer
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
// replace 'plugin' with 'FooPlugin' in context
|
||||
// sensitive manner.
|
||||
func (w *writer) replace(in, target string) (bool, string) {
|
||||
if !strings.Contains(in, target) {
|
||||
return false, ""
|
||||
}
|
||||
newer := strings.Replace(
|
||||
target, "plugin", w.root+"Plugin", 1)
|
||||
return true, strings.Replace(in, target, newer, 1)
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Helm chart inflator
|
||||
|
||||
#
|
||||
# Reads a file like this
|
||||
#
|
||||
# apiVersion: kustomize.config.k8s.io/v1
|
||||
@@ -23,6 +24,7 @@ set -e
|
||||
# Example execution:
|
||||
# ./plugin/someteam.example.com/v1/ChartInflator configFile.yaml
|
||||
|
||||
set -e
|
||||
|
||||
# Yaml parsing is a ridiculous thing to do in bash,
|
||||
# but let's try:
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
// TODO: Download and inflate the chart, and check that
|
||||
// in for the test.
|
||||
func TestChartInflator(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildExecPlugin(
|
||||
@@ -1,20 +1,5 @@
|
||||
// +build plugin
|
||||
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package main
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// +build plugin
|
||||
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
var database = map[string]string{
|
||||
"TREE": "oak",
|
||||
"ROCKET": "Saturn V",
|
||||
"FRUIT": "apple",
|
||||
"VEGETABLE": "carrot",
|
||||
"SIMPSON": "homer",
|
||||
}
|
||||
|
||||
type plugin struct{}
|
||||
|
||||
var KVSource plugin
|
||||
|
||||
func (p plugin) Get(
|
||||
root string, args []string) (map[string]string, error) {
|
||||
r := make(map[string]string)
|
||||
for _, k := range args {
|
||||
v, ok := database[k]
|
||||
if ok {
|
||||
r[k] = v
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
25
plugin/someteam.example.com/v1/kvmaker/kvMaker.go
Normal file
25
plugin/someteam.example.com/v1/kvmaker/kvMaker.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package kvmaker
|
||||
|
||||
var database = map[string]string{
|
||||
"TREE": "oak",
|
||||
"ROCKET": "Saturn V",
|
||||
"FRUIT": "apple",
|
||||
"VEGETABLE": "carrot",
|
||||
"SIMPSON": "homer",
|
||||
}
|
||||
|
||||
type plugin struct{}
|
||||
|
||||
var KVSource plugin
|
||||
|
||||
func (p plugin) Get(
|
||||
root string, args []string) (map[string]string, error) {
|
||||
r := make(map[string]string)
|
||||
for _, k := range args {
|
||||
v, ok := database[k]
|
||||
if ok {
|
||||
r[k] = v
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestSedTransformer(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildExecPlugin("someteam.example.com", "v1", "SedTransformer")
|
||||
@@ -1,5 +1,3 @@
|
||||
// +build plugin
|
||||
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestSomeServiceGeneratorPlugin(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
@@ -1,5 +1,3 @@
|
||||
// +build plugin
|
||||
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Reference in New Issue
Block a user