mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Dogfood the plugin framework.
This PR:
* provides a code generator that converts
kustomize Go plugins to normal code, i.e.
the plugin appears as
t := builtin.NewImageTagTransformer()
instead of
p := plugin.Open("imagetagtransformer.so")
s := p.Lookup(someSymbol)
t, ok = s.(Transformer)
* converts the main processing thread in
kusttarget.go to use those factory calls to run
builtin generators and transformer before
calling user-supplied plugins,
* as an example, provides an imagetag transformer
plugin, converting a legacy transformer to
builtin plugin form with its own isolated test.
This test can be expanded by moving more code
into it, but that can be done in a later PR.
Writing core functionality as plugins assures a
maintained plugin authoring and testing framework,
assures modularity, provides meaningful plugin
examples, and gives us a means to make informed
choices on which kustomize packages to publish
(and which to move to internal/). The code
generator allows all this without losing "go get
sigs.k8s.io/kustomize" functionality.
TODO:
1) Convert remaining legacy transformers to
plugins (patch SMP/JSON, name prefix/suffix,
labels/annos) with their own tests. The
generators are already done; this PR wires
them up, and all tests & examples pass.
2) Push code down into the plugins, as the first
pass at conversion writes plugins as thin
layers over calls into code under the mess
that is pkg/. Once this is done, we can
reasonably move all the packages that aren't
imported by plugins to internal/.
This PR could be split in two, one to merge the
the generator, and the second to merge the
ImageTagTransformer plugin and its wiring into the
main flow.
The latter PR could then serve as an example for
converting the remaining transformers.
This commit is contained in:
46
bin/pluginator.sh
Executable file
46
bin/pluginator.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/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.
|
||||
@@ -46,6 +46,10 @@ function testExamples {
|
||||
mdrip --mode test --label test README.md ./examples
|
||||
}
|
||||
|
||||
function generateCode {
|
||||
./bin/pluginator.sh $oldGoPath
|
||||
}
|
||||
|
||||
# Use of GOPATH is optional if go modules are
|
||||
# used. This script tries to work for people who
|
||||
# don't have GOPATH set, and work for travis.
|
||||
@@ -90,6 +94,7 @@ echo pwd=`pwd`
|
||||
echo " "
|
||||
echo "Working..."
|
||||
|
||||
runFunc generateCode
|
||||
runFunc testGoLangCILint
|
||||
runFunc testGoTest
|
||||
|
||||
|
||||
338
cmd/pluginator/main.go
Normal file
338
cmd/pluginator/main.go
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
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)
|
||||
}
|
||||
@@ -231,16 +231,6 @@ func (kt *KustTarget) AccumulateTarget() (
|
||||
return nil, errors.Wrapf(
|
||||
err, "merging CRDs %v", crdTc)
|
||||
}
|
||||
resMap, err := kt.generateConfigMapsAndSecrets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(
|
||||
err, "generating legacy configMaps and secrets")
|
||||
}
|
||||
err = ra.MergeResourcesWithOverride(resMap)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(
|
||||
err, "merging legacy configMaps and secrets")
|
||||
}
|
||||
err = kt.generateFromPlugins(ra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -265,14 +255,29 @@ func (kt *KustTarget) AccumulateTarget() (
|
||||
|
||||
func (kt *KustTarget) generateFromPlugins(
|
||||
ra *accumulator.ResAccumulator) error {
|
||||
generators, err := kt.loadGeneratorPlugins()
|
||||
generators, err := kt.configureBuiltinGenerators()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, g := range generators {
|
||||
resMap, err := g.Generate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// The legacy generators allow override.
|
||||
err = ra.MergeResourcesWithOverride(resMap)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "merging from generator %v", g)
|
||||
}
|
||||
}
|
||||
generators, err = kt.loadGeneratorPlugins()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "loading generator plugins")
|
||||
}
|
||||
for _, g := range generators {
|
||||
resMap, err := g.Generate()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "generating from %v", g)
|
||||
return err
|
||||
}
|
||||
err = ra.MergeResourcesWithErrorOnIdCollision(resMap)
|
||||
if err != nil {
|
||||
@@ -282,26 +287,6 @@ func (kt *KustTarget) generateFromPlugins(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) generateConfigMapsAndSecrets() (resmap.ResMap, error) {
|
||||
cms, err := kt.rFactory.NewResMapFromConfigMapArgs(
|
||||
kt.ldr,
|
||||
kt.kustomization.GeneratorOptions,
|
||||
kt.kustomization.ConfigMapGenerator)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(
|
||||
err, "configmapgenerator: %v", kt.kustomization.ConfigMapGenerator)
|
||||
}
|
||||
secrets, err := kt.rFactory.NewResMapFromSecretArgs(
|
||||
kt.ldr,
|
||||
kt.kustomization.GeneratorOptions,
|
||||
kt.kustomization.SecretGenerator)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(
|
||||
err, "secretgenerator: %v", kt.kustomization.SecretGenerator)
|
||||
}
|
||||
return resmap.MergeWithErrorOnIdCollision(cms, secrets)
|
||||
}
|
||||
|
||||
// accumulateResources fills the given resourceAccumulator
|
||||
// with resources read from the given list of paths.
|
||||
func (kt *KustTarget) accumulateResources(
|
||||
@@ -397,11 +382,11 @@ func (kt *KustTarget) newTransformer(
|
||||
return nil, err
|
||||
}
|
||||
r = append(r, t)
|
||||
t, err = transformers.NewImageTransformer(kt.kustomization.Images, tConfig.Images)
|
||||
lts, err := kt.configureBuiltinTransformers(tConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r = append(r, t)
|
||||
r = append(r, lts...)
|
||||
tp, err := kt.loadTransformerPlugins()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
165
pkg/target/kusttarget_configplugin.go
Normal file
165
pkg/target/kusttarget_configplugin.go
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
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 target
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/pkg/image"
|
||||
"sigs.k8s.io/kustomize/pkg/plugins"
|
||||
"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/yaml"
|
||||
)
|
||||
|
||||
// Functions dedicated to configuring the builtin
|
||||
// transformer and generator plugins using config data
|
||||
// read from a kustomization file.
|
||||
//
|
||||
// Non-builtin plugins will get their configuration
|
||||
// from their own dedicated structs and yaml files.
|
||||
//
|
||||
// There are some loops in the functions below because
|
||||
// the kustomization file would, say, allow one to
|
||||
// request multiple secrets be made, or run multiple
|
||||
// image tag transforms, so we need to run the plugins
|
||||
// N times (plugins are easier to write, configure and
|
||||
// test if they do just one thing).
|
||||
//
|
||||
// TODO: Push code down into the plugins, as the first pass
|
||||
// at this writes plugins as thin layers over calls
|
||||
// into existing packages. The builtin plugins should
|
||||
// be viewed as examples, and the packages they access
|
||||
// directory should be public, while everything else
|
||||
// should go into internal.
|
||||
|
||||
type generatorConfigurator func() ([]transformers.Generator, error)
|
||||
type transformerConfigurator func(
|
||||
tConfig *config.TransformerConfig) ([]transformers.Transformer, error)
|
||||
|
||||
func (kt *KustTarget) configureBuiltinGenerators() (
|
||||
[]transformers.Generator, error) {
|
||||
configurators := []generatorConfigurator{
|
||||
kt.configureBuiltinConfigMapGenerator,
|
||||
kt.configureBuiltinSecretGenerator,
|
||||
}
|
||||
var result []transformers.Generator
|
||||
for _, f := range configurators {
|
||||
r, err := f()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, r...)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinTransformers(
|
||||
tConfig *config.TransformerConfig) (
|
||||
[]transformers.Transformer, error) {
|
||||
// TODO: Convert remaining legacy transformers to plugins
|
||||
// (patch SMP/JSON, name prefix/suffix, labels/annos).
|
||||
// with tests.
|
||||
configurators := []transformerConfigurator{
|
||||
kt.configureBuiltinImageTagTransformer,
|
||||
}
|
||||
var result []transformers.Transformer
|
||||
for _, f := range configurators {
|
||||
r, err := f(tConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, r...)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinSecretGenerator() (
|
||||
result []transformers.Generator, err error) {
|
||||
var c struct {
|
||||
types.GeneratorOptions
|
||||
types.SecretArgs
|
||||
}
|
||||
if kt.kustomization.GeneratorOptions != nil {
|
||||
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
|
||||
}
|
||||
for _, args := range kt.kustomization.SecretGenerator {
|
||||
c.SecretArgs = args
|
||||
p := builtingen.NewSecretGeneratorPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "secret")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinConfigMapGenerator() (
|
||||
result []transformers.Generator, err error) {
|
||||
var c struct {
|
||||
types.GeneratorOptions
|
||||
types.ConfigMapArgs
|
||||
}
|
||||
if kt.kustomization.GeneratorOptions != nil {
|
||||
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
|
||||
}
|
||||
for _, args := range kt.kustomization.ConfigMapGenerator {
|
||||
c.ConfigMapArgs = args
|
||||
p := builtingen.NewConfigMapGeneratorPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "configmap")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinImageTagTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
var c struct {
|
||||
ImageTag image.Image
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
for _, args := range kt.kustomization.Images {
|
||||
c.ImageTag = args
|
||||
c.FieldSpecs = tConfig.Images
|
||||
p := builtingen.NewImageTagTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "imageTag")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinPlugin(
|
||||
p plugins.Configurable, c interface{}, id string) error {
|
||||
y, err := yaml.Marshal(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "builtin %s marshal", id)
|
||||
}
|
||||
err = p.Config(kt.ldr, kt.rFactory, y)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "builtin %s config: %v", id, y)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -16,6 +16,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/cmd/pluginator
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
56
plugin/builtin/ImageTagTransformer.go
Normal file
56
plugin/builtin/ImageTagTransformer.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// +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.
|
||||
*/
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/cmd/pluginator
|
||||
package main
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/pkg/image"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Find matching image declarations and replace
|
||||
// the name, tag and/or digest.
|
||||
type plugin struct {
|
||||
ImageTag image.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
var KustomizePlugin plugin
|
||||
|
||||
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 *plugin) Transform(m resmap.ResMap) error {
|
||||
argsList := make([]image.Image, 1)
|
||||
argsList[0] = p.ImageTag
|
||||
t, err := transformers.NewImageTransformer(argsList, p.FieldSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.Transform(m)
|
||||
}
|
||||
|
||||
91
plugin/builtin/ImageTagTransformer_test.go
Normal file
91
plugin/builtin/ImageTagTransformer_test.go
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2018 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_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/internal/plugintest"
|
||||
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
|
||||
"sigs.k8s.io/kustomize/pkg/kusttest"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
)
|
||||
|
||||
func TestImageTagTransformer(t *testing.T) {
|
||||
tc := plugintest_test.NewPluginTestEnv(t).Set()
|
||||
defer tc.Reset()
|
||||
|
||||
tc.BuildGoPlugin(
|
||||
"builtin", "", "ImageTagTransformer")
|
||||
|
||||
th := kusttest_test.NewKustTestHarnessFull(
|
||||
t, "/app", loader.RestrictionRootOnly, plugin.ActivePluginConfig())
|
||||
|
||||
rm := th.LoadAndRunTransformer(`
|
||||
apiVersion: builtin
|
||||
kind: ImageTagTransformer
|
||||
metadata:
|
||||
name: notImportantHere
|
||||
imageTag:
|
||||
name: nginx
|
||||
newTag: v2
|
||||
`,`
|
||||
group: apps
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deploy1
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
initContainers:
|
||||
- name: nginx2
|
||||
image: my-nginx:1.8.0
|
||||
- name: init-alpine
|
||||
image: alpine:1.8.0
|
||||
containers:
|
||||
- name: ngnix
|
||||
image: nginx:1.7.9
|
||||
- name: repliaced-with-digest
|
||||
image: foobar:1
|
||||
- name: postgresdb
|
||||
image: postgres:1.8.0
|
||||
`)
|
||||
|
||||
th.AssertActualEqualsExpected(rm, `
|
||||
apiVersion: v1
|
||||
group: apps
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deploy1
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:v2
|
||||
name: ngnix
|
||||
- image: foobar:1
|
||||
name: repliaced-with-digest
|
||||
- image: postgres:1.8.0
|
||||
name: postgresdb
|
||||
initContainers:
|
||||
- image: my-nginx:1.8.0
|
||||
name: nginx2
|
||||
- image: alpine:1.8.0
|
||||
name: init-alpine
|
||||
`)
|
||||
}
|
||||
@@ -16,6 +16,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
//go:generate go run sigs.k8s.io/kustomize/cmd/pluginator
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
37
plugin/builtingen/ConfigMapGenerator.go
Normal file
37
plugin/builtingen/ConfigMapGenerator.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Code generated by pluginator on ConfigMapGenerator; DO NOT EDIT.
|
||||
package builtingen
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type ConfigMapGeneratorPlugin struct {
|
||||
ldr ifc.Loader
|
||||
rf *resmap.Factory
|
||||
types.GeneratorOptions
|
||||
types.ConfigMapArgs
|
||||
}
|
||||
|
||||
func NewConfigMapGeneratorPlugin() *ConfigMapGeneratorPlugin {
|
||||
return &ConfigMapGeneratorPlugin{}
|
||||
}
|
||||
|
||||
func (p *ConfigMapGeneratorPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.GeneratorOptions = types.GeneratorOptions{}
|
||||
p.ConfigMapArgs = types.ConfigMapArgs{}
|
||||
err = yaml.Unmarshal(config, p)
|
||||
p.ldr = ldr
|
||||
p.rf = rf
|
||||
return
|
||||
}
|
||||
|
||||
func (p *ConfigMapGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
argsList := make([]types.ConfigMapArgs, 1)
|
||||
argsList[0] = p.ConfigMapArgs
|
||||
return p.rf.NewResMapFromConfigMapArgs(
|
||||
p.ldr, &p.GeneratorOptions, argsList)
|
||||
}
|
||||
40
plugin/builtingen/ImageTagTransformer.go
Normal file
40
plugin/builtingen/ImageTagTransformer.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// Code generated by pluginator on ImageTagTransformer; DO NOT EDIT.
|
||||
package builtingen
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/pkg/image"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Find matching image declarations and replace
|
||||
// the name, tag and/or digest.
|
||||
type ImageTagTransformerPlugin struct {
|
||||
ImageTag image.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
func NewImageTagTransformerPlugin() *ImageTagTransformerPlugin {
|
||||
return &ImageTagTransformerPlugin{}
|
||||
}
|
||||
|
||||
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 *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
argsList := make([]image.Image, 1)
|
||||
argsList[0] = p.ImageTag
|
||||
t, err := transformers.NewImageTransformer(argsList, p.FieldSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.Transform(m)
|
||||
}
|
||||
|
||||
37
plugin/builtingen/SecretGenerator.go
Normal file
37
plugin/builtingen/SecretGenerator.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Code generated by pluginator on SecretGenerator; DO NOT EDIT.
|
||||
package builtingen
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type SecretGeneratorPlugin struct {
|
||||
ldr ifc.Loader
|
||||
rf *resmap.Factory
|
||||
types.GeneratorOptions
|
||||
types.SecretArgs
|
||||
}
|
||||
|
||||
func NewSecretGeneratorPlugin() *SecretGeneratorPlugin {
|
||||
return &SecretGeneratorPlugin{}
|
||||
}
|
||||
|
||||
func (p *SecretGeneratorPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.GeneratorOptions = types.GeneratorOptions{}
|
||||
p.SecretArgs = types.SecretArgs{}
|
||||
err = yaml.Unmarshal(config, p)
|
||||
p.ldr = ldr
|
||||
p.rf = rf
|
||||
return
|
||||
}
|
||||
|
||||
func (p *SecretGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
argsList := make([]types.SecretArgs, 1)
|
||||
argsList[0] = p.SecretArgs
|
||||
return p.rf.NewResMapFromSecretArgs(
|
||||
p.ldr, &p.GeneratorOptions, argsList)
|
||||
}
|
||||
Reference in New Issue
Block a user