Remove some duped code.

This commit is contained in:
jregan
2019-04-06 16:04:04 -07:00
parent 38029d1836
commit b32e041bfe
11 changed files with 106 additions and 129 deletions

View File

@@ -32,8 +32,8 @@ type Registry struct {
} }
const ( const (
TransformerSymbol = "Transformer" PluginSymbol = "KustomizePlugin"
PluginsDir = "plugins" PluginRoot = "plugins"
pluginTypeGo = types.PluginType("go") pluginTypeGo = types.PluginType("go")
pluginTypeBuiltIn = types.PluginType("builtin") pluginTypeBuiltIn = types.PluginType("builtin")
) )
@@ -48,7 +48,7 @@ func DefaultPluginConfig() *types.PluginConfig {
return &types.PluginConfig{ return &types.PluginConfig{
GoEnabled: false, GoEnabled: false,
DirectoryPath: filepath.Join( DirectoryPath: filepath.Join(
pgmconfig.ConfigRoot(), PluginsDir), pgmconfig.ConfigRoot(), PluginRoot),
} }
} }

View File

@@ -18,81 +18,40 @@ package plugins
import ( import (
"fmt" "fmt"
"path/filepath" "sigs.k8s.io/kustomize/pkg/transformers"
"plugin" "sigs.k8s.io/kustomize/pkg/types"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
) )
const generatorSymbol = "Generator"
type Generatable interface {
Generate() (resmap.ResMap, error)
}
type generatorLoader struct { type generatorLoader struct {
pluginDir string pc *types.PluginConfig
enabled bool
rf *resmap.Factory
} }
func NewGeneratorLoader(b bool, f *resmap.Factory) generatorLoader { func NewGeneratorLoader(pc *types.PluginConfig) generatorLoader {
return generatorLoader{ return generatorLoader{pc: pc}
pluginDir: filepath.Join(pgmconfig.ConfigRoot(), pgmconfig.PluginsDir),
enabled: b,
rf: f,
}
} }
func (l generatorLoader) Load(rm resmap.ResMap) (resmap.ResMap, error) { func (l generatorLoader) Load(
rm resmap.ResMap) ([]transformers.Generator, error) {
if len(rm) == 0 { if len(rm) == 0 {
return nil, nil return nil, nil
} }
if !l.enabled { if !l.pc.GoEnabled {
return nil, fmt.Errorf("plugin is not enabled") return nil, fmt.Errorf("plugins not enabled")
} }
var result resmap.ResMap var result []transformers.Generator
for id, res := range rm { for id, res := range rm {
r, err := l.load(id, res) fileName := pluginFileName(l.pc, id)
c, err := loadAndConfigurePlugin(fileName, res)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result, err = resmap.MergeWithErrorOnIdCollision(result, r) g, ok := c.(transformers.Generator)
if err != nil { if !ok {
return nil, err return nil, fmt.Errorf("plugin %s not a generator", fileName)
} }
result = append(result, g)
} }
return result, nil return result, nil
} }
func (l generatorLoader) load(id resid.ResId, res *resource.Resource) (resmap.ResMap, error) {
fileName := filepath.Join(l.pluginDir, 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(generatorSymbol)
if err != nil {
return nil, fmt.Errorf("plugin %s fails lookup", fileName)
}
c, ok := symbol.(Configurable)
if !ok {
return nil, fmt.Errorf("plugin %s not configurable", fileName)
}
err = c.Config(res)
if err != nil {
return nil, errors.Wrapf(err, "plugin %s fails configuration", fileName)
}
g, ok := c.(Generatable)
if !ok {
return nil, fmt.Errorf("plugin %s not a transformer", fileName)
}
return g.Generate()
}

View File

@@ -43,7 +43,8 @@ func NewTransformerLoader(pc *types.PluginConfig) transformerLoader {
return transformerLoader{pc: pc} return transformerLoader{pc: pc}
} }
func (l transformerLoader) Load(rm resmap.ResMap) ([]transformers.Transformer, error) { func (l transformerLoader) Load(
rm resmap.ResMap) ([]transformers.Transformer, error) {
if len(rm) == 0 { if len(rm) == 0 {
return nil, nil return nil, nil
} }
@@ -52,30 +53,37 @@ func (l transformerLoader) Load(rm resmap.ResMap) ([]transformers.Transformer, e
} }
var result []transformers.Transformer var result []transformers.Transformer
for id, res := range rm { for id, res := range rm {
t, err := l.load(id, res) fileName := pluginFileName(l.pc, id)
c, err := loadAndConfigurePlugin(fileName, res)
if err != nil { if err != nil {
return nil, err return nil, err
} }
t, ok := c.(transformers.Transformer)
if !ok {
return nil, fmt.Errorf("plugin %s not a transformer", fileName)
}
result = append(result, t) result = append(result, t)
} }
return result, nil return result, nil
} }
func (l transformerLoader) load( func pluginFileName(pc *types.PluginConfig, id resid.ResId) string {
id resid.ResId, res *resource.Resource) (transformers.Transformer, error) { return filepath.Join(
fileName := filepath.Join( pc.DirectoryPath,
l.pc.DirectoryPath,
id.Gvk().Group, id.Gvk().Version, id.Gvk().Kind+".so") id.Gvk().Group, id.Gvk().Version, id.Gvk().Kind+".so")
}
func loadAndConfigurePlugin(
fileName string, res *resource.Resource) (Configurable, error) {
goPlugin, err := plugin.Open(fileName) goPlugin, err := plugin.Open(fileName)
if err != nil { if err != nil {
return nil, fmt.Errorf("plugin %s file not opened", fileName) return nil, fmt.Errorf("plugin %s file not opened", fileName)
} }
symbol, err := goPlugin.Lookup(kplugin.PluginSymbol)
symbol, err := goPlugin.Lookup(kplugin.TransformerSymbol)
if err != nil { if err != nil {
return nil, fmt.Errorf("plugin %s fails lookup", fileName) return nil, fmt.Errorf(
"plugin %s doesn't have symbol %s", fileName, kplugin.PluginSymbol)
} }
c, ok := symbol.(Configurable) c, ok := symbol.(Configurable)
if !ok { if !ok {
return nil, fmt.Errorf("plugin %s not configurable", fileName) return nil, fmt.Errorf("plugin %s not configurable", fileName)
@@ -84,10 +92,5 @@ func (l transformerLoader) load(
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "plugin %s fails configuration", fileName) return nil, errors.Wrapf(err, "plugin %s fails configuration", fileName)
} }
return c, nil
t, ok := c.(transformers.Transformer)
if !ok {
return nil, fmt.Errorf("plugin %s not a transformer", fileName)
}
return t, nil
} }

View File

@@ -14,17 +14,14 @@ limitations under the License.
package target_test package target_test
import ( import (
"os"
"path/filepath"
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/types"
) )
func writeGenerator(th *KustTestHarness, path string) { func writeGenerator(th *KustTestHarness, path string) {
th.writeF(path, ` th.writeF(path, `
apiVersion: strings.microwoosh.com/v1 apiVersion: someteam.example.com/v1
kind: ServiceGenerator kind: ServiceGenerator
metadata: metadata:
name: myServiceGenerator name: myServiceGenerator
@@ -34,20 +31,14 @@ port: "12345"
} }
func TestGeneratorPlugin(t *testing.T) { func TestGeneratorPlugin(t *testing.T) {
dir, err := filepath.Abs("../../..") tc := NewTestEnvController(t).Set()
if err != nil { defer tc.Reset()
t.Errorf("unexpected error %v", err)
}
os.Setenv(pgmconfig.XDG_CONFIG_HOME, dir)
defer os.Unsetenv(pgmconfig.XDG_CONFIG_HOME)
err = buildGoPlugins(dir, "ServiceGenerator") tc.BuildGoPlugin(
if err != nil { "someteam.example.com", "v1", "ServiceGenerator")
t.Errorf("unexpected error %v", err)
}
th := NewKustTestHarnessWithPluginConfig( th := NewKustTestHarnessWithPluginConfig(
t, "/app", types.PluginConfig{GoEnabled: true}) t, "/app", plugin.ActivePluginConfig())
th.writeK("/app", ` th.writeK("/app", `
generators: generators:
- serviceGenerator.yaml - serviceGenerator.yaml

View File

@@ -173,17 +173,6 @@ func (kt *KustTarget) AccumulateTarget() ( // nolint: gocyclo
if err != nil { if err != nil {
errs.Append(errors.Wrap(err, "MergeResourcesWithErrorOnIdCollision")) errs.Append(errors.Wrap(err, "MergeResourcesWithErrorOnIdCollision"))
} }
resourceFromGenerators, err := kt.loadGeneratorPlugins()
if err != nil {
errs.Append(errors.Wrap(err, "failed to load resources from generators"))
}
if len(errs.Get()) > 0 {
return ra, errs
}
err = ra.MergeResourcesWithErrorOnIdCollision(resourceFromGenerators)
if err != nil {
errs.Append(errors.Wrap(err, "MergeResourcesWithErrorOnIdCollision"))
}
tConfig, err := config.MakeTransformerConfig( tConfig, err := config.MakeTransformerConfig(
kt.ldr, kt.kustomization.Configurations) kt.ldr, kt.kustomization.Configurations)
if err != nil { if err != nil {
@@ -213,6 +202,12 @@ func (kt *KustTarget) AccumulateTarget() ( // nolint: gocyclo
if err != nil { if err != nil {
return nil, err return nil, err
} }
if kt.pluginConfig.GoEnabled {
kt.generateFromPlugins(ra, errs)
if len(errs.Get()) > 0 {
return ra, errs
}
}
patches, err := kt.rFactory.RF().SliceFromPatches( patches, err := kt.rFactory.RF().SliceFromPatches(
kt.ldr, kt.kustomization.PatchesStrategicMerge) kt.ldr, kt.kustomization.PatchesStrategicMerge)
if err != nil { if err != nil {
@@ -232,6 +227,26 @@ func (kt *KustTarget) AccumulateTarget() ( // nolint: gocyclo
return ra, nil return ra, nil
} }
func (kt *KustTarget) generateFromPlugins(
ra *accumulator.ResAccumulator,
errs *interror.KustomizationErrors) {
generators, err := kt.loadGeneratorPlugins()
if err != nil {
errs.Append(err)
}
for _, g := range generators {
resMap, err := g.Generate()
if err != nil {
errs.Append(err)
} else {
err = ra.MergeResourcesWithErrorOnIdCollision(resMap)
if err != nil {
errs.Append(errors.Wrap(err, "from plugin"))
}
}
}
}
func (kt *KustTarget) generateConfigMapsAndSecrets( func (kt *KustTarget) generateConfigMapsAndSecrets(
errs *interror.KustomizationErrors) (resmap.ResMap, error) { errs *interror.KustomizationErrors) (resmap.ResMap, error) {
cms, err := kt.rFactory.NewResMapFromConfigMapArgs( cms, err := kt.rFactory.NewResMapFromConfigMapArgs(
@@ -345,20 +360,19 @@ func (kt *KustTarget) newTransformer(
} }
func (kt *KustTarget) loadTransformerPlugins() ([]transformers.Transformer, error) { func (kt *KustTarget) loadTransformerPlugins() ([]transformers.Transformer, error) {
transformerPluginConfigs, err := kt.rFactory.FromFiles( configs, err := kt.rFactory.FromFiles(
kt.ldr, kt.kustomization.Transformers) kt.ldr, kt.kustomization.Transformers)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return plugins.NewTransformerLoader(kt.pluginConfig).Load(transformerPluginConfigs) return plugins.NewTransformerLoader(kt.pluginConfig).Load(configs)
} }
func (kt *KustTarget) loadGeneratorPlugins() (resmap.ResMap, error) { func (kt *KustTarget) loadGeneratorPlugins() ([]transformers.Generator, error) {
generatorPluginConfigs, err := kt.rFactory.FromFiles( configs, err := kt.rFactory.FromFiles(
kt.ldr, kt.kustomization.Generators) kt.ldr, kt.kustomization.Generators)
if err != nil { if err != nil {
return nil, err return nil, err
} }
gl := plugins.NewGeneratorLoader(kt.goPluginEnabled, kt.rFactory) return plugins.NewGeneratorLoader(kt.pluginConfig).Load(configs)
return gl.Load(generatorPluginConfigs)
} }

View File

@@ -105,7 +105,7 @@ func (x *TestEnvController) BuildGoPlugin(plugin ...string) {
// ObjectRoot is the objRoot dir for plugin object files. // ObjectRoot is the objRoot dir for plugin object files.
func (x *TestEnvController) ObjectRoot() string { func (x *TestEnvController) ObjectRoot() string {
return filepath.Join( return filepath.Join(
x.xdgConfigHome, pgmconfig.PgmName, plugin.PluginsDir) x.xdgConfigHome, pgmconfig.PgmName, plugin.PluginRoot)
} }
// SrcRoot is a objRoot directory for plugin source code // SrcRoot is a objRoot directory for plugin source code
@@ -120,7 +120,7 @@ func (x *TestEnvController) ObjectRoot() string {
func (x *TestEnvController) SrcRoot() string { func (x *TestEnvController) SrcRoot() string {
dir := filepath.Join( dir := filepath.Join(
os.Getenv("GOPATH"), "src", os.Getenv("GOPATH"), "src",
pgmconfig.Repo, pgmconfig.PgmName, plugin.PluginsDir) pgmconfig.Repo, pgmconfig.PgmName, plugin.PluginRoot)
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {
x.t.Errorf("plugin source objRoot '%s' not found", dir) x.t.Errorf("plugin source objRoot '%s' not found", dir)
} }

View File

@@ -26,3 +26,8 @@ type Transformer interface {
// Transform modifies data in the argument, e.g. adding labels to resources that can be labelled. // Transform modifies data in the argument, e.g. adding labels to resources that can be labelled.
Transform(m resmap.ResMap) error Transform(m resmap.ResMap) error
} }
// A Generator creates an instance of resmap.ResMap.
type Generator interface {
Generate() (resmap.ResMap, error)
}

View File

@@ -13,7 +13,7 @@ import (
type plugin struct{} type plugin struct{}
var Transformer plugin var KustomizePlugin plugin
func (p *plugin) Config(k ifc.Kunstructured) error { func (p *plugin) Config(k ifc.Kunstructured) error {
return nil return nil

View File

@@ -1,3 +1,5 @@
// +build plugin
package main package main
import ( import (
@@ -15,7 +17,7 @@ type plugin struct {
Port string Port string
} }
var Generator plugin var KustomizePlugin plugin
var manifest = ` var manifest = `
apiVersion: v1 apiVersion: v1

View File

@@ -18,11 +18,11 @@ import (
"sigs.k8s.io/kustomize/pkg/transformers/config" "sigs.k8s.io/kustomize/pkg/transformers/config"
) )
type plugin struct{ type plugin struct {
prefix string prefix string
} }
var Transformer plugin var KustomizePlugin plugin
func (p *plugin) Config(k ifc.Kunstructured) error { func (p *plugin) Config(k ifc.Kunstructured) error {
var err error var err error

View File

@@ -1,24 +1,27 @@
// +build plugin // +build plugin
package main package main
var database = map[string]string{ var database = map[string]string{
"TREE": "oak", "TREE": "oak",
"ROCKET": "Saturn V", "ROCKET": "Saturn V",
"FRUIT": "apple", "FRUIT": "apple",
"VEGETABLE": "carrot", "VEGETABLE": "carrot",
"SIMPSON": "homer", "SIMPSON": "homer",
} }
type plugin struct{} type plugin struct{}
var KVSource plugin var KVSource plugin
func (p plugin) Get( func (p plugin) Get(
root string, args []string) (map[string]string, error) { root string, args []string) (map[string]string, error) {
r := make(map[string]string) r := make(map[string]string)
for _, k := range args { for _, k := range args {
v, ok := database[k] v, ok := database[k]
if ok { if ok {
r[k] = v r[k] = v
} }
} }
return r, nil return r, nil
} }