mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
One plugin per dir.
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Converts Go-based kustomize plugins in
|
||||
# sigs.k8s.io/kustomize/plugin/builtin
|
||||
# (all in package 'main') to generator and
|
||||
# transformer factory functions in
|
||||
# sigs.k8s.io/kustomize/plugin/builtingen
|
||||
# (all in package 'builtingen').
|
||||
#
|
||||
# Cannot put all these in the same dir, since
|
||||
# plugins must be in the 'main' package,
|
||||
# the factory functions cannot be in 'main',
|
||||
# Go disallows multiple packages in one dir.
|
||||
|
||||
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
|
||||
|
||||
/bin/rm -rf plugin/builtingen
|
||||
mkdir plugin/builtingen
|
||||
GOPATH=$myGoPath go generate --tags plugin \
|
||||
sigs.k8s.io/kustomize/plugin/builtin
|
||||
ls -C1 plugin/builtingen
|
||||
|
||||
popd >& /dev/null
|
||||
|
||||
echo All done.
|
||||
@@ -47,7 +47,7 @@ function testExamples {
|
||||
}
|
||||
|
||||
function generateCode {
|
||||
./bin/pluginator.sh $oldGoPath
|
||||
./plugin/generateBuiltins.sh $oldGoPath
|
||||
}
|
||||
|
||||
# Use of GOPATH is optional if go modules are
|
||||
|
||||
@@ -1,338 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// pluginator is a code generator that converts
|
||||
// kustomize generator (G) and/or transformer (T)
|
||||
// Go plugins to statically linkable code.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// 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 PLUGIN CONVENTIONS
|
||||
//
|
||||
// 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
|
||||
// those functions implement the Configurable,
|
||||
// Generator and Transformer interfaces.
|
||||
//
|
||||
// Converting the plugin file to a normal .go package
|
||||
// file is a matter string substitution permitted
|
||||
// by the following conventions.
|
||||
//
|
||||
// * Configuration of builtin plugins:
|
||||
//
|
||||
// Config file looks like
|
||||
//
|
||||
// ---------------------------------------------
|
||||
// apiVersion: builtin
|
||||
// kind: SecretGenerator
|
||||
// metadata:
|
||||
// name: whatever
|
||||
// otherFields: whatever
|
||||
// ---------------------------------------------
|
||||
//
|
||||
// The apiVersion must be 'builtin'.
|
||||
//
|
||||
// For non-builtins the apiVersion can be any legal
|
||||
// apiVersion value, e.g. 'someteam.example.com/v1beta1'
|
||||
//
|
||||
// The builtin source must be at:
|
||||
//
|
||||
// ${repo}/plugin/${apiVersion}/${kind}.go
|
||||
//
|
||||
// where repo=$GOPATH/src/sigs.k8s.io/kustomize
|
||||
//
|
||||
// k8s wants 'kind' values to follow CamelCase,
|
||||
// while Go style wants (but doesn't demand)
|
||||
// lowercase file names.
|
||||
//
|
||||
// kustomize will accept either idiom, but the Go file
|
||||
// name must be ${kind}.go (CamelCase allowed).
|
||||
//
|
||||
// * Source follows this pattern
|
||||
//
|
||||
// ---------------------------------------------
|
||||
// // +build plugin
|
||||
//
|
||||
// //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,
|
||||
// k ifc.Kunstructured) error {...}
|
||||
// func (p *plugin) Generate(
|
||||
// ) (resmap.ResMap, error) {...}
|
||||
// func (p *plugin) Transform(
|
||||
// m resmap.ResMap) error {...}
|
||||
// ---------------------------------------------
|
||||
//
|
||||
// - The 2nd line must be empty.
|
||||
// - One may `go fmt` this file.
|
||||
// - There's no mention of 'SecretGenerator'
|
||||
// in this file; that binding is done by
|
||||
// the plugin loader or pluginator.
|
||||
//
|
||||
// * To compile this for loading as a Go plugin:
|
||||
//
|
||||
// repo=$GOPATH/src/sigs.k8s.io/kustomize
|
||||
// dir=$repo/plugin/builtin
|
||||
// go build -buildmode plugin -tags=plugin \
|
||||
// -o $dir/SecretGenerator.so \
|
||||
// $dir/SecretGenerator.go
|
||||
//
|
||||
// * To generate code:
|
||||
//
|
||||
// repo=$GOPATH/src/sigs.k8s.io/kustomize
|
||||
// cd $repo/plugin/builtin
|
||||
// go generate --tags plugin .
|
||||
//
|
||||
// This creates
|
||||
//
|
||||
// $repo/plugin/builtingen/SecretGenerator.go
|
||||
//
|
||||
// etc.
|
||||
//
|
||||
// * Generated plugins are used in kustomize via
|
||||
//
|
||||
// ---------------------------------------------
|
||||
// package whatever
|
||||
// import "sigs.k8s.io/kustomize/plugin/builtingen
|
||||
// ...
|
||||
// g := builtingen.NewSecretGenerator()
|
||||
// g.Config(l, rf, k)
|
||||
// resources, err := g.Generate()
|
||||
// err = g.Transform(resources)
|
||||
// // Eventually emit resources.
|
||||
// ---------------------------------------------
|
||||
//
|
||||
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 := fileRoot()
|
||||
file, err := os.Open(root + ".go")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
processBoilerPlate(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 builtingen")
|
||||
|
||||
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 fileRoot() 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 processBoilerPlate(s *bufio.Scanner, f string) {
|
||||
if !s.Scan() {
|
||||
log.Fatalf("1: %s not long enough", f)
|
||||
}
|
||||
first := s.Text()
|
||||
if !s.Scan() {
|
||||
log.Fatalf("2: %s not long enough", f)
|
||||
}
|
||||
next := s.Text()
|
||||
if !hasPluginTag(first, next) {
|
||||
log.Fatalf("%s lacks plugin tag", f)
|
||||
}
|
||||
gotMain := false
|
||||
for !gotMain && s.Scan() {
|
||||
next = s.Text()
|
||||
gotMain = strings.HasPrefix(next, "package main")
|
||||
}
|
||||
if !gotMain {
|
||||
log.Fatalf("%s missing package main", f)
|
||||
}
|
||||
}
|
||||
|
||||
func hasPluginTag(first, next string) bool {
|
||||
return strings.HasPrefix(first, "// +build plugin") &&
|
||||
len(next) == 0
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
root string
|
||||
f *os.File
|
||||
}
|
||||
|
||||
func NewWriter(r string) *writer {
|
||||
n := makeSrcFileName(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 makeSrcFileName(root string) string {
|
||||
return filepath.Join(
|
||||
os.Getenv("GOPATH"),
|
||||
"src",
|
||||
pgmconfig.DomainName,
|
||||
pgmconfig.ProgramName,
|
||||
pgmconfig.PluginRoot,
|
||||
"builtingen",
|
||||
root+".go")
|
||||
}
|
||||
|
||||
func (w *writer) close() { 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)
|
||||
}
|
||||
@@ -87,8 +87,8 @@ to a sea of objects that kustomize transforms and
|
||||
emits.
|
||||
|
||||
The specified order of transformers in the
|
||||
`transformers` field is, however, respected, as
|
||||
transformers aren't expected to be commutative.
|
||||
`transformers` field should be respected, as
|
||||
transformers cannot be expected to be commutative.
|
||||
|
||||
## Execution
|
||||
|
||||
@@ -115,7 +115,8 @@ other [k8s object]), kustomize will first look for an
|
||||
_executable_ file called
|
||||
|
||||
```
|
||||
$XDG_CONFIG_HOME/kustomize/plugin/${apiVersion}/${kind}
|
||||
$XDG_CONFIG_HOME/kustomize/plugin
|
||||
/${apiVersion}/LOWERCASE(${kind})/${kind}
|
||||
```
|
||||
|
||||
The default value of `XDG_CONFIG_HOME` is `$HOME/.config`.
|
||||
@@ -150,7 +151,7 @@ reminder.
|
||||
|
||||
### Exec plugins
|
||||
|
||||
[chartinflator]: ../plugin/someteam.example.com/v1/ChartInflator
|
||||
[chartinflator]: ../plugin/someteam.example.com/v1/chartinflator/ChartInflator
|
||||
|
||||
See this example [helm chart inflator][chartInflator].
|
||||
|
||||
@@ -183,15 +184,13 @@ marshalled resources on `stdin` and capture
|
||||
### Go plugins
|
||||
|
||||
[Go plugin]: https://golang.org/pkg/plugin/
|
||||
[secretgenerator]: ../plugin/builtin/SecretGenerator.go
|
||||
[servicegenerator]: ../plugin/someteam.example.com/v1/someservicegenerator/SomeServiceGenerator.go
|
||||
|
||||
See this example [secret generator][secretGenerator].
|
||||
See this example [service generator][serviceGenerator].
|
||||
|
||||
A [Go plugin] for kustomize looks like this:
|
||||
|
||||
> ```
|
||||
> +build plugin
|
||||
>
|
||||
> package main
|
||||
>
|
||||
> import (
|
||||
@@ -205,8 +204,9 @@ A [Go plugin] for kustomize looks like this:
|
||||
> var KustomizePlugin plugin
|
||||
>
|
||||
> func (p *plugin) Config(
|
||||
> ldr ifc.Loader, rf *resmap.Factory,
|
||||
> k ifc.Kunstructured) error {...}
|
||||
> ldr ifc.Loader,
|
||||
> rf *resmap.Factory,
|
||||
> c []byte) error {...}
|
||||
>
|
||||
> func (p *plugin) Generate() (resmap.ResMap, error) {...}
|
||||
>
|
||||
@@ -218,7 +218,7 @@ The use of the identifiers `plugin`,
|
||||
`Configurable`, `Generator`, `Transformer` as
|
||||
shown is _required_.
|
||||
|
||||
The plugin author should of course change the
|
||||
The plugin author will change the
|
||||
contents of the `plugin` struct, and the three
|
||||
method bodies, and add imports as desired.
|
||||
|
||||
@@ -227,10 +227,8 @@ source code is sitting right next to where the
|
||||
shared object (`.so`) files are expected to be:
|
||||
|
||||
```
|
||||
dir=$XDG_CONFIG_HOME/kustomize/plugin/${apiVersion}
|
||||
go build -buildmode plugin -tags=plugin \
|
||||
-o $dir/${kind}.so \
|
||||
$dir/${kind}.go
|
||||
d=$XDG_CONFIG_HOME/kustomize/plugin/${apiVersion}/LOWERCASE(${kind})
|
||||
go build -buildmode plugin -o $d/${kind}.so $d/${kind}.go
|
||||
```
|
||||
|
||||
#### Caveats
|
||||
@@ -241,9 +239,9 @@ Go plugins allow kustomize extensions that
|
||||
uses to test its _builtin_ generators and
|
||||
transformers,
|
||||
|
||||
* run without the performance hit of firing up a
|
||||
subprocess and marshalling/unmarshalling data
|
||||
for each plugin run.
|
||||
* run without the performance cost of firing up a
|
||||
subprocess and marshalling/unmarshalling all
|
||||
resource data for each plugin run.
|
||||
|
||||
[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||
|
||||
@@ -263,3 +261,12 @@ a failure at load time.
|
||||
|
||||
Exec plugins also lack provenance, but don't
|
||||
suffer from the skew problem.
|
||||
|
||||
In either case, at the time of writing the proper
|
||||
way to share a plugin is as a tar file of source code
|
||||
and associated data, developed and unpacked under
|
||||
`kustomize/plugin`. In the case of a Go plugin, the
|
||||
end user must compile it (described above), and may
|
||||
need to compile kustomize as well. If people use
|
||||
Go plugins, more tooling will be built to make
|
||||
plugin sharing easier.
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
|
||||
@@ -95,7 +96,8 @@ func goBin() string {
|
||||
// Compile reads ${srcRoot}/${g}/${v}/${k}.go
|
||||
// and writes ${objRoot}/${g}/${v}/${k}.so
|
||||
func (b *Compiler) Compile(g, v, k string) error {
|
||||
objDir := filepath.Join(b.objRoot, g, v)
|
||||
lowK := strings.ToLower(k)
|
||||
objDir := filepath.Join(b.objRoot, g, v, lowK)
|
||||
objFile := filepath.Join(objDir, k) + ".so"
|
||||
if RecentFileExists(objFile) {
|
||||
// Skip rebuilding it.
|
||||
@@ -105,7 +107,7 @@ func (b *Compiler) Compile(g, v, k string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcFile := filepath.Join(b.srcRoot, g, v, k) + ".go"
|
||||
srcFile := filepath.Join(b.srcRoot, g, v, lowK, k) + ".go"
|
||||
if !FileExists(srcFile) {
|
||||
return fmt.Errorf(
|
||||
"cannot find source %s", srcFile)
|
||||
@@ -114,7 +116,6 @@ func (b *Compiler) Compile(g, v, k string) error {
|
||||
"build",
|
||||
"-buildmode",
|
||||
"plugin",
|
||||
"-tags=plugin",
|
||||
"-o", objFile, srcFile,
|
||||
}
|
||||
goBin := goBin()
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestCompiler(t *testing.T) {
|
||||
|
||||
expectObj := filepath.Join(
|
||||
c.ObjRoot(),
|
||||
"someteam.example.com", "v1", "DatePrefixer.so")
|
||||
"someteam.example.com", "v1", "dateprefixer", "DatePrefixer.so")
|
||||
if FileExists(expectObj) {
|
||||
t.Errorf("obj file should not exist yet: %s", expectObj)
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func TestCompiler(t *testing.T) {
|
||||
|
||||
expectObj = filepath.Join(
|
||||
c.ObjRoot(),
|
||||
"builtin", "", "SecretGenerator.so")
|
||||
"builtin", "", "secretgenerator", "SecretGenerator.so")
|
||||
if FileExists(expectObj) {
|
||||
t.Errorf("obj file should not exist yet: %s", expectObj)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
@@ -39,8 +38,8 @@ const (
|
||||
// ExecPlugin record the name and args of an executable
|
||||
// It triggers the executable generator and transformer
|
||||
type ExecPlugin struct {
|
||||
// name of the executable
|
||||
name string
|
||||
// absolute path of the executable
|
||||
path string
|
||||
|
||||
// Optional command line arguments to the executable
|
||||
// pulled from specially named fields in cfg.
|
||||
@@ -57,15 +56,13 @@ type ExecPlugin struct {
|
||||
ldr ifc.Loader
|
||||
}
|
||||
|
||||
func NewExecPlugin(root string, id resid.ResId) *ExecPlugin {
|
||||
return &ExecPlugin{
|
||||
name: filepath.Join(root, pluginPath(id)),
|
||||
}
|
||||
func NewExecPlugin(p string) *ExecPlugin {
|
||||
return &ExecPlugin{path: p}
|
||||
}
|
||||
|
||||
// isAvailable checks to see if the plugin is available
|
||||
func (p *ExecPlugin) isAvailable() bool {
|
||||
f, err := os.Stat(p.name)
|
||||
f, err := os.Stat(p.path)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
@@ -164,7 +161,7 @@ func (p *ExecPlugin) invokePlugin(input []byte) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd := exec.Command(p.name, args...)
|
||||
cmd := exec.Command(p.path, args...)
|
||||
cmd.Env = p.getEnv()
|
||||
cmd.Stdin = bytes.NewReader(input)
|
||||
cmd.Stderr = os.Stderr
|
||||
@@ -226,7 +223,7 @@ func (p *ExecPlugin) updateResMapValues(output []byte, rm resmap.ResMap) error {
|
||||
idString, ok := annotations[idAnnotation]
|
||||
if !ok {
|
||||
return fmt.Errorf("the transformer %s should not remove annotation %s",
|
||||
p.name, idAnnotation)
|
||||
p.path, idAnnotation)
|
||||
}
|
||||
id := resid.ResId{}
|
||||
err := yaml.Unmarshal([]byte(idString), &id)
|
||||
|
||||
@@ -51,8 +51,9 @@ s/$BAR/bar/g
|
||||
`))
|
||||
|
||||
p := NewExecPlugin(
|
||||
plugin.DefaultPluginConfig().DirectoryPath,
|
||||
pluginConfig.Id())
|
||||
AbsolutePluginPath(
|
||||
plugin.DefaultPluginConfig(),
|
||||
pluginConfig.Id()))
|
||||
|
||||
yaml, err := pluginConfig.AsYAML()
|
||||
if err != nil {
|
||||
@@ -60,9 +61,9 @@ s/$BAR/bar/g
|
||||
}
|
||||
p.Config(ldr, rf, yaml)
|
||||
|
||||
expected := "/kustomize/plugin/someteam.example.com/v1/SedTransformer"
|
||||
if !strings.HasSuffix(p.name, expected) {
|
||||
t.Fatalf("expected suffix '%s', got '%s'", expected, p.name)
|
||||
expected := "/kustomize/plugin/someteam.example.com/v1/sedtransformer/SedTransformer"
|
||||
if !strings.HasSuffix(p.path, expected) {
|
||||
t.Fatalf("expected suffix '%s', got '%s'", expected, p.path)
|
||||
}
|
||||
|
||||
expected = `apiVersion: someteam.example.com/v1
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"plugin"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
@@ -96,8 +97,20 @@ func (l *Loader) LoadTransformer(
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func pluginPath(id resid.ResId) string {
|
||||
return filepath.Join(id.Gvk().Group, id.Gvk().Version, id.Gvk().Kind)
|
||||
func relativePluginPath(id resid.ResId) string {
|
||||
return filepath.Join(
|
||||
id.Gvk().Group,
|
||||
id.Gvk().Version,
|
||||
strings.ToLower(id.Gvk().Kind))
|
||||
}
|
||||
|
||||
func AbsolutePluginPath(pc *types.PluginConfig, id resid.ResId) string {
|
||||
return filepath.Join(
|
||||
pc.DirectoryPath, relativePluginPath(id), id.Gvk().Kind)
|
||||
}
|
||||
|
||||
func (l *Loader) absolutePluginPath(id resid.ResId) string {
|
||||
return AbsolutePluginPath(l.pc, id)
|
||||
}
|
||||
|
||||
func (l *Loader) loadAndConfigurePlugin(
|
||||
@@ -106,7 +119,8 @@ func (l *Loader) loadAndConfigurePlugin(
|
||||
return nil, errors.Errorf(
|
||||
"plugins not enabled, but trying to load %s", res.Id())
|
||||
}
|
||||
if p := NewExecPlugin(l.pc.DirectoryPath, res.Id()); p.isAvailable() {
|
||||
if p := NewExecPlugin(
|
||||
l.absolutePluginPath(res.Id())); p.isAvailable() {
|
||||
c = p
|
||||
} else {
|
||||
c, err = l.loadGoPlugin(res.Id())
|
||||
@@ -135,26 +149,26 @@ func (l *Loader) loadAndConfigurePlugin(
|
||||
var registry = make(map[string]Configurable)
|
||||
|
||||
func (l *Loader) loadGoPlugin(id resid.ResId) (c Configurable, err error) {
|
||||
regId := relativePluginPath(id)
|
||||
var ok bool
|
||||
path := pluginPath(id)
|
||||
if c, ok = registry[path]; ok {
|
||||
if c, ok = registry[regId]; ok {
|
||||
return c, nil
|
||||
}
|
||||
name := filepath.Join(l.pc.DirectoryPath, path)
|
||||
p, err := plugin.Open(name + ".so")
|
||||
absPath := l.absolutePluginPath(id)
|
||||
p, err := plugin.Open(absPath + ".so")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "plugin %s fails to load", name)
|
||||
return nil, errors.Wrapf(err, "plugin %s fails to load", absPath)
|
||||
}
|
||||
symbol, err := p.Lookup(PluginSymbol)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(
|
||||
err, "plugin %s doesn't have symbol %s",
|
||||
name, PluginSymbol)
|
||||
regId, PluginSymbol)
|
||||
}
|
||||
c, ok = symbol.(Configurable)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin %s not configurable", name)
|
||||
return nil, fmt.Errorf("plugin %s not configurable", regId)
|
||||
}
|
||||
registry[path] = c
|
||||
registry[regId] = c
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ port: "12345"
|
||||
)
|
||||
|
||||
func TestLoader(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
// TODO: Download and inflate the chart, and check that
|
||||
// in for the test.
|
||||
func TestChartInflatorPlugin(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildExecPlugin(
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
/*
|
||||
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 target
|
||||
|
||||
@@ -23,7 +10,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/plugin/builtingen"
|
||||
"sigs.k8s.io/kustomize/plugin/builtin"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
@@ -104,7 +91,7 @@ func (kt *KustTarget) configureBuiltinSecretGenerator() (
|
||||
}
|
||||
for _, args := range kt.kustomization.SecretGenerator {
|
||||
c.SecretArgs = args
|
||||
p := builtingen.NewSecretGeneratorPlugin()
|
||||
p := builtin.NewSecretGeneratorPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "secret")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -125,7 +112,7 @@ func (kt *KustTarget) configureBuiltinConfigMapGenerator() (
|
||||
}
|
||||
for _, args := range kt.kustomization.ConfigMapGenerator {
|
||||
c.ConfigMapArgs = args
|
||||
p := builtingen.NewConfigMapGeneratorPlugin()
|
||||
p := builtin.NewConfigMapGeneratorPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "configmap")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -146,7 +133,7 @@ func (kt *KustTarget) configureBuiltinNameTransformer(
|
||||
c.Prefix = kt.kustomization.NamePrefix
|
||||
c.Suffix = kt.kustomization.NameSuffix
|
||||
c.FieldSpecs = tConfig.NamePrefix
|
||||
p := builtingen.NewNameTransformerPlugin()
|
||||
p := builtin.NewNameTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "name")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -165,7 +152,7 @@ func (kt *KustTarget) configureBuiltinImageTagTransformer(
|
||||
for _, args := range kt.kustomization.Images {
|
||||
c.ImageTag = args
|
||||
c.FieldSpecs = tConfig.Images
|
||||
p := builtingen.NewImageTagTransformerPlugin()
|
||||
p := builtin.NewImageTagTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "imageTag")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
)
|
||||
|
||||
func TestPluginDir(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildExecPlugin(
|
||||
|
||||
@@ -47,7 +47,7 @@ metadata:
|
||||
}
|
||||
|
||||
func TestOrderedTransformers(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
@@ -92,7 +92,7 @@ spec:
|
||||
}
|
||||
|
||||
func TestSedTransformer(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildExecPlugin(
|
||||
@@ -161,7 +161,7 @@ metadata:
|
||||
}
|
||||
|
||||
func TestTransformedTransformers(t *testing.T) {
|
||||
tc := plugin.NewPluginTestEnv(t).Set()
|
||||
tc := plugin.NewEnvForTest(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
|
||||
@@ -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