Cleanup plugin builds.

This commit is contained in:
jregan
2019-04-05 12:06:48 -07:00
parent cb4af7a9d4
commit 16fe7ced6a
18 changed files with 267 additions and 111 deletions

View File

@@ -18,6 +18,7 @@ package configmapandsecret
import (
"fmt"
"sort"
"strings"
"github.com/pkg/errors"
@@ -101,13 +102,24 @@ func (bf baseFactory) keyValuesFromPlugins(sources []types.KVSource) ([]kv.Pair,
if err != nil {
return nil, err
}
for k, v := range kvs {
result = append(result, kv.Pair{Key: k, Value: v})
for _, k := range sortedKeys(kvs) {
result = append(result, kv.Pair{Key: k, Value: kvs[k]})
}
}
return result, nil
}
func sortedKeys(m map[string]string) []string {
keys := make([]string, len(m))
i := 0
for k := range m {
keys[i] = k
i++
}
sort.Strings(keys)
return keys
}
func (bf baseFactory) keyValuesFromFileSources(sources []string) ([]kv.Pair, error) {
var kvs []kv.Pair
for _, s := range sources {

View File

@@ -77,14 +77,14 @@ func TestKeyValuesFromPlugins(t *testing.T) {
},
},
expected: []kv.Pair{
{
Key: "FOO",
Value: "bar",
},
{
Key: "BAR",
Value: "baz",
},
{
Key: "FOO",
Value: "bar",
},
},
},
{

View File

@@ -93,7 +93,7 @@ func (kf *KunstructuredFactoryImpl) MakeConfigMap(
o, err := configmapandsecret.NewFactory(
ldr, options,
plugin.NewConfiguredRegistry(
ldr, &kf.generatorMetaArgs.PluginConfig)).MakeConfigMap(args)
ldr, kf.generatorMetaArgs.PluginConfig)).MakeConfigMap(args)
if err != nil {
return nil, err
}
@@ -108,7 +108,7 @@ func (kf *KunstructuredFactoryImpl) MakeSecret(
o, err := configmapandsecret.NewFactory(
ldr, options,
plugin.NewConfiguredRegistry(
ldr, &kf.generatorMetaArgs.PluginConfig)).MakeSecret(args)
ldr, kf.generatorMetaArgs.PluginConfig)).MakeSecret(args)
if err != nil {
return nil, err
}

View File

@@ -19,6 +19,7 @@ package plugin
import (
"fmt"
"path/filepath"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/types"
@@ -31,13 +32,20 @@ type Registry struct {
}
const (
TransformerSymbol = "Transformer"
PluginsDir = "plugins"
pluginTypeGo = types.PluginType("go")
pluginTypeBuiltIn = types.PluginType("builtin")
)
func DefaultPluginConfig() types.PluginConfig {
return types.PluginConfig{
func ActivePluginConfig() *types.PluginConfig {
pc := DefaultPluginConfig()
pc.GoEnabled = true
return pc
}
func DefaultPluginConfig() *types.PluginConfig {
return &types.PluginConfig{
GoEnabled: false,
DirectoryPath: filepath.Join(
pgmconfig.ConfigRoot(), PluginsDir),

View File

@@ -27,6 +27,7 @@ import (
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/target"
"sigs.k8s.io/kustomize/pkg/types"
)
// Options contain the options for running a build
@@ -63,7 +64,7 @@ func NewCmdBuild(
out io.Writer, fs fs.FileSystem,
rf *resmap.Factory,
ptf transformer.Factory,
b bool) *cobra.Command {
pc *types.PluginConfig) *cobra.Command {
var o Options
cmd := &cobra.Command{
@@ -76,7 +77,7 @@ func NewCmdBuild(
if err != nil {
return err
}
return o.RunBuild(out, fs, rf, ptf, b)
return o.RunBuild(out, fs, rf, ptf, pc)
},
}
cmd.Flags().StringVarP(
@@ -104,13 +105,13 @@ func (o *Options) Validate(args []string) error {
func (o *Options) RunBuild(
out io.Writer, fSys fs.FileSystem,
rf *resmap.Factory, ptf transformer.Factory,
b bool) error {
pc *types.PluginConfig) error {
ldr, err := loader.NewLoader(o.kustomizationPath, fSys)
if err != nil {
return err
}
defer ldr.Cleanup()
kt, err := target.NewKustTarget(ldr, rf, ptf, b)
kt, err := target.NewKustTarget(ldr, rf, ptf, pc)
if err != nil {
return err
}

View File

@@ -20,7 +20,6 @@ package commands
import (
"flag"
"os"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
@@ -31,6 +30,7 @@ import (
"sigs.k8s.io/kustomize/pkg/commands/edit"
"sigs.k8s.io/kustomize/pkg/commands/misc"
"sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/types"
@@ -50,25 +50,26 @@ See https://sigs.k8s.io/kustomize
`,
}
// Configuration for ConfigMap and Secret generators.
genMetaArgs := types.GeneratorMetaArgs{
PluginConfig: plugin.DefaultPluginConfig(),
}
pluginConfig := plugin.DefaultPluginConfig()
c.PersistentFlags().BoolVar(
&genMetaArgs.PluginConfig.GoEnabled,
&pluginConfig.GoEnabled,
plugin.EnableGoPluginsFlagName,
false, plugin.EnableGoPluginsFlagHelp)
// Not advertising this alpha feature.
c.PersistentFlags().MarkHidden(plugin.EnableGoPluginsFlagName)
// Configuration for ConfigMap and Secret generators.
genMetaArgs := types.GeneratorMetaArgs{
PluginConfig: pluginConfig,
}
uf := kunstruct.NewKunstructuredFactoryWithGeneratorArgs(&genMetaArgs)
c.AddCommand(
build.NewCmdBuild(
stdOut, fSys,
resmap.NewFactory(resource.NewFactory(uf)),
transformer.NewFactoryImpl(), genMetaArgs.PluginConfig.GoEnabled),
transformer.NewFactoryImpl(), pluginConfig),
edit.NewCmdEdit(fSys, validator.NewKustValidator(), uf),
misc.NewCmdConfig(fSys),
misc.NewCmdVersion(stdOut),

View File

@@ -28,6 +28,6 @@ var KustomizationFileNames = []string{
}
const (
PgmName = "kustomize"
PluginsDir = "plugins"
PgmName = "kustomize"
Repo = "sigs.k8s.io"
)

View File

@@ -22,38 +22,33 @@ import (
"plugin"
"github.com/pkg/errors"
kplugin "sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/transformers"
"sigs.k8s.io/kustomize/pkg/types"
)
const transformerSymbol = "Transformer"
type Configurable interface {
Config(k ifc.Kunstructured) error
}
type transformerLoader struct {
pluginDir string
enabled bool
pc *types.PluginConfig
}
func NewTransformerLoader(b bool) transformerLoader {
return transformerLoader{
pluginDir: filepath.Join(pgmconfig.ConfigRoot(), pgmconfig.PluginsDir),
enabled: b,
}
func NewTransformerLoader(pc *types.PluginConfig) transformerLoader {
return transformerLoader{pc: pc}
}
func (l transformerLoader) Load(rm resmap.ResMap) ([]transformers.Transformer, error) {
if len(rm) == 0 {
return nil, nil
}
if !l.enabled {
return nil, fmt.Errorf("plugin is not enabled")
if !l.pc.GoEnabled {
return nil, fmt.Errorf("plugins not enabled")
}
var result []transformers.Transformer
for id, res := range rm {
@@ -66,14 +61,17 @@ func (l transformerLoader) Load(rm resmap.ResMap) ([]transformers.Transformer, e
return result, nil
}
func (l transformerLoader) load(id resid.ResId, res *resource.Resource) (transformers.Transformer, error) {
fileName := filepath.Join(l.pluginDir, id.Gvk().Kind+".so")
func (l transformerLoader) load(
id resid.ResId, res *resource.Resource) (transformers.Transformer, error) {
fileName := filepath.Join(
l.pc.DirectoryPath,
id.Gvk().Group, id.Gvk().Version, id.Gvk().Kind+".so")
goPlugin, err := plugin.Open(fileName)
if err != nil {
return nil, fmt.Errorf("plugin %s file not opened", fileName)
}
symbol, err := goPlugin.Lookup(transformerSymbol)
symbol, err := goPlugin.Lookup(kplugin.TransformerSymbol)
if err != nil {
return nil, fmt.Errorf("plugin %s fails lookup", fileName)
}

View File

@@ -15,9 +15,10 @@ package target_test
import (
"path/filepath"
"sigs.k8s.io/kustomize/pkg/types"
"strings"
"testing"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
)
func TestGeneratorOptionsWithBases(t *testing.T) {
@@ -96,7 +97,7 @@ secretGenerator:
func TestGoPluginDoesNotExist(t *testing.T) {
th := NewKustTestHarnessWithPluginConfig(
t, "/app", types.PluginConfig{GoEnabled: true})
t, "/app", plugin.ActivePluginConfig())
th.writeK("/app", `
secretGenerator:
- name: attemptGoPlugin

View File

@@ -41,11 +41,11 @@ import (
// KustTarget encapsulates the entirety of a kustomization build.
type KustTarget struct {
kustomization *types.Kustomization
ldr ifc.Loader
rFactory *resmap.Factory
tFactory transformer.Factory
goPluginEnabled bool
kustomization *types.Kustomization
ldr ifc.Loader
rFactory *resmap.Factory
tFactory transformer.Factory
pluginConfig *types.PluginConfig
}
// NewKustTarget returns a new instance of KustTarget primed with a Loader.
@@ -53,7 +53,7 @@ func NewKustTarget(
ldr ifc.Loader,
rFactory *resmap.Factory,
tFactory transformer.Factory,
b bool) (*KustTarget, error) {
pc *types.PluginConfig) (*KustTarget, error) {
content, err := loadKustFile(ldr)
if err != nil {
return nil, err
@@ -71,11 +71,11 @@ func NewKustTarget(
strings.Join(errs, "\n"), ldr.Root())
}
return &KustTarget{
kustomization: &k,
ldr: ldr,
rFactory: rFactory,
tFactory: tFactory,
goPluginEnabled: b,
kustomization: &k,
ldr: ldr,
rFactory: rFactory,
tFactory: tFactory,
pluginConfig: pc,
}, nil
}
@@ -256,7 +256,7 @@ func (kt *KustTarget) accumulateBases() (
continue
}
subKt, err := NewKustTarget(
ldr, kt.rFactory, kt.tFactory, kt.goPluginEnabled)
ldr, kt.rFactory, kt.tFactory, kt.pluginConfig)
if err != nil {
errs.Append(errors.Wrap(err, "couldn't make target for "+path))
ldr.Cleanup()
@@ -323,11 +323,13 @@ func (kt *KustTarget) newTransformer(
}
r = append(r, t)
tp, err := kt.loadTransformerPlugins()
if err != nil {
return nil, err
if kt.pluginConfig.GoEnabled {
tp, err := kt.loadTransformerPlugins()
if err != nil {
return nil, err
}
r = append(r, tp...)
}
r = append(r, tp...)
return transformers.NewMultiTransformer(r), nil
}
@@ -337,6 +339,5 @@ func (kt *KustTarget) loadTransformerPlugins() ([]transformers.Transformer, erro
if err != nil {
return nil, err
}
tl := plugins.NewTransformerLoader(kt.goPluginEnabled)
return tl.Load(transformerPluginConfigs)
return plugins.NewTransformerLoader(kt.pluginConfig).Load(transformerPluginConfigs)
}

View File

@@ -23,6 +23,7 @@ import (
"strings"
"testing"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
@@ -204,7 +205,9 @@ func TestResources(t *testing.T) {
}
func TestKustomizationNotFound(t *testing.T) {
_, err := NewKustTarget(loadertest.NewFakeLoader("/foo"), nil, nil, false)
_, err := NewKustTarget(
loadertest.NewFakeLoader("/foo"),
nil, nil, plugin.DefaultPluginConfig())
if err == nil {
t.Fatalf("expected an error")
}

View File

@@ -21,11 +21,11 @@ package target_test
import (
"fmt"
"path/filepath"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"strings"
"testing"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/k8sdeps/transformer"
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
@@ -40,7 +40,7 @@ type KustTestHarness struct {
t *testing.T
rf *resmap.Factory
ldr loadertest.FakeLoader
b bool
pc *types.PluginConfig
}
func NewKustTestHarness(t *testing.T, path string) *KustTestHarness {
@@ -50,19 +50,19 @@ func NewKustTestHarness(t *testing.T, path string) *KustTestHarness {
func NewKustTestHarnessWithPluginConfig(
t *testing.T, path string,
config types.PluginConfig) *KustTestHarness {
pc *types.PluginConfig) *KustTestHarness {
return &KustTestHarness{
t: t,
rf: resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryWithGeneratorArgs(
&types.GeneratorMetaArgs{PluginConfig: config}))),
&types.GeneratorMetaArgs{PluginConfig: pc}))),
ldr: loadertest.NewFakeLoader(path),
b: config.GoEnabled}
pc: pc}
}
func (th *KustTestHarness) makeKustTarget() *KustTarget {
kt, err := NewKustTarget(
th.ldr, th.rf, transformer.NewFactoryImpl(), th.b)
th.ldr, th.rf, transformer.NewFactoryImpl(), th.pc)
if err != nil {
th.t.Fatalf("Unexpected construction error %v", err)
}

View 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_test
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
)
// TestEnvController manages the KustTarget test environment.
// It sets/resets XDG_CONFIG_HOME, makes/removes a temp objRoot.
type TestEnvController struct {
t *testing.T
xdgConfigHome string
oldXdg string
wasSet bool
}
func NewTestEnvController(t *testing.T) *TestEnvController {
return &TestEnvController{t: t}
}
func (x *TestEnvController) Set() *TestEnvController {
x.makeTmpConfigHomeDir()
x.makeObjectRootDir()
x.setEnv()
return x
}
func (x *TestEnvController) Reset() {
x.resetEnv()
x.removeTmpConfigHomeDir()
}
func (x *TestEnvController) fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
func (x *TestEnvController) recentFileExists(path string) bool {
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false
}
}
age := time.Now().Sub(fi.ModTime())
return age.Minutes() < 1
}
func (x *TestEnvController) BuildGoPlugin(plugin ...string) {
obj := filepath.Join(
append([]string{x.ObjectRoot()}, plugin...)...) + ".so"
if x.recentFileExists(obj) {
// Skip rebuilding it.
return
}
src := filepath.Join(
append([]string{x.SrcRoot()}, plugin...)...) + ".go"
if !x.fileExists(src) {
x.t.Errorf("cannot find go plugin source %s", src)
}
commands := []string{
"build",
"-buildmode",
"plugin",
"-tags=plugin",
"-o", obj, src,
}
goBin := filepath.Join(os.Getenv("GOROOT"), "bin", "go")
if !x.fileExists(src) {
x.t.Errorf("cannot find go compiler %s", goBin)
}
cmd := exec.Command(goBin, commands...)
cmd.Env = os.Environ()
// cmd.Dir = filepath.Join(dir, "kustomize", "plugins")
if err := cmd.Run(); err != nil {
x.t.Errorf("compiler error building %s: %v", src, err)
}
}
// ObjectRoot is the objRoot dir for plugin object files.
func (x *TestEnvController) ObjectRoot() string {
return filepath.Join(
x.xdgConfigHome, pgmconfig.PgmName, plugin.PluginsDir)
}
// SrcRoot is a objRoot directory for plugin source code
// used by tests.
//
// Plugin object code files have to be in a particular
// location to be found and loaded for security reasons,
// but placement of plugin source code is up to the user.
//
// This function returns a location for storing example
// plugins for tests. And maybe builtins at some point.
func (x *TestEnvController) SrcRoot() string {
dir := filepath.Join(
os.Getenv("GOPATH"), "src",
pgmconfig.Repo, pgmconfig.PgmName, plugin.PluginsDir)
if _, err := os.Stat(dir); err != nil {
x.t.Errorf("plugin source objRoot '%s' not found", dir)
}
return dir
}
func (x *TestEnvController) makeTmpConfigHomeDir() {
var err error
x.xdgConfigHome, err = ioutil.TempDir("", "kustomizetests")
if err != nil {
x.t.Errorf("failed to make temp objRoot: %v", err)
}
}
func (x *TestEnvController) makeObjectRootDir() {
err := os.MkdirAll(x.ObjectRoot(), os.ModePerm)
if err != nil {
x.t.Errorf(
"making temp object objRoot %s: %v", x.ObjectRoot(), err)
}
}
func (x *TestEnvController) removeTmpConfigHomeDir() {
err := os.RemoveAll(x.xdgConfigHome)
if err != nil {
x.t.Errorf(
"removing temp object objRoot: %s %v", x.xdgConfigHome, err)
}
}
func (x *TestEnvController) setEnv() {
x.oldXdg, x.wasSet = os.LookupEnv(pgmconfig.XDG_CONFIG_HOME)
os.Setenv(pgmconfig.XDG_CONFIG_HOME, x.xdgConfigHome)
}
func (x *TestEnvController) resetEnv() {
if x.wasSet {
os.Setenv(pgmconfig.XDG_CONFIG_HOME, x.oldXdg)
} else {
os.Unsetenv(pgmconfig.XDG_CONFIG_HOME)
}
}

View File

@@ -14,14 +14,9 @@ limitations under the License.
package target_test
import (
"os"
"os/exec"
"path/filepath"
"testing"
"fmt"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/types"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
)
func writeDeployment(th *KustTestHarness, path string) {
@@ -44,7 +39,7 @@ spec:
func writeStringPrefixer(th *KustTestHarness, path string) {
th.writeF(path, `
apiVersion: strings.microwoosh.com/v1
apiVersion: someteam.example.com/v1
kind: StringPrefixer
metadata:
name: myStringPrefixer
@@ -54,54 +49,25 @@ prefix: apple-
func writeDatePrefixer(th *KustTestHarness, path string) {
th.writeF(path, `
apiVersion: team.dater.com/v1
apiVersion: someteam.example.com/v1
kind: DatePrefixer
metadata:
name: myDatePrefixer
`)
}
func buildGoPlugins(dir, filename string) error {
commands := []string{
"build",
"-buildmode",
"plugin",
"-tags=plugin",
"-o",
filename + ".so",
filename + ".go",
}
goBin := filepath.Join(os.Getenv("GOROOT"), "bin", "go")
if _, err := os.Stat(goBin); err != nil {
return fmt.Errorf("go binary not found %s", goBin)
}
cmd := exec.Command(goBin, commands...)
cmd.Env = os.Environ()
cmd.Dir = filepath.Join(dir, "kustomize", "plugins")
return cmd.Run()
}
func TestOrderedTransformers(t *testing.T) {
dir, err := filepath.Abs("../../..")
if err != nil {
t.Errorf("unexpected error %v", err)
}
os.Setenv(pgmconfig.XDG_CONFIG_HOME, dir)
defer os.Unsetenv(pgmconfig.XDG_CONFIG_HOME)
tc := NewTestEnvController(t).Set()
defer tc.Reset()
err = buildGoPlugins(dir, "StringPrefixer")
if err != nil {
t.Errorf("unexpected error %v", err)
}
tc.BuildGoPlugin(
"someteam.example.com", "v1", "StringPrefixer")
err = buildGoPlugins(dir, "DatePrefixer")
if err != nil {
t.Errorf("unexpected error %v", err)
}
tc.BuildGoPlugin(
"someteam.example.com", "v1", "DatePrefixer")
th := NewKustTestHarnessWithPluginConfig(
t, "/app", types.PluginConfig{GoEnabled: true})
t, "/app", plugin.ActivePluginConfig())
th.writeK("/app", `
resources:
- deployment.yaml
@@ -134,7 +100,7 @@ spec:
func xTestTransformedTransformers(t *testing.T) {
th := NewKustTestHarnessWithPluginConfig(
t, "/app/overlay", types.PluginConfig{GoEnabled: true})
t, "/app/overlay", plugin.ActivePluginConfig())
th.writeK("/app/base", `
resources:

View File

@@ -203,7 +203,7 @@ type GeneratorArgs struct {
// GeneratorMetaArgs contains arguments common to generators
// that come from somewhere other than a kustomization file.
type GeneratorMetaArgs struct {
PluginConfig PluginConfig
PluginConfig *PluginConfig
}
// PluginConfig holds plugin configuration.