mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-22 06:47:00 +00:00
Merge pull request #1075 from monopole/pluginDogfooding
Dogfood the plugin framework.
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