Skip to content

Commit

Permalink
Ease doing custom configuration of builtin plugins.
Browse files Browse the repository at this point in the history
  • Loading branch information
monopole committed Sep 13, 2019
1 parent 7e71009 commit 2050afd
Show file tree
Hide file tree
Showing 33 changed files with 588 additions and 424 deletions.
36 changes: 31 additions & 5 deletions cmd/pluginator/main.go
Expand Up @@ -16,6 +16,15 @@ import (
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)

//go:generate stringer -type=pluginType
type pluginType int

const (
unknown pluginType = iota
Transformer
Generator
)

func main() {
root := inputFileRoot()
file, err := os.Open(root + ".go")
Expand All @@ -34,24 +43,41 @@ func main() {
fmt.Sprintf(
"// Code generated by pluginator on %s; DO NOT EDIT.",
root))
w.write("package builtin")
w.write("package " + plugins.BuiltinPluginPackage)

pType := unknown

for scanner.Scan() {
l := scanner.Text()
if strings.HasPrefix(l, "//go:generate") {
continue
}
if strings.HasPrefix(l, "//noinspection") {
continue
}
if l == "var "+plugins.PluginSymbol+" plugin" {
w.write("func New" + root + "Plugin() *" + root + "Plugin {")
w.write(" return &" + root + "Plugin{}")
w.write("}")
continue
}
if strings.Contains(l, " Transform(") {
if pType != unknown {
log.Fatal("unexpected Transform(")
}
pType = Transformer
} else if strings.Contains(l, " Generate(") {
if pType != unknown {
log.Fatal("unexpected Generate(")
}
pType = Generator
}
w.write(l)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
w.write("")
w.write("func New" + root + "Plugin() resmap." + pType.String() + "Plugin {")
w.write(" return &" + root + "Plugin{}")
w.write("}")
}

func inputFileRoot() string {
Expand Down Expand Up @@ -93,7 +119,7 @@ func makeOutputFileName(root string) string {
pgmconfig.DomainName,
pgmconfig.ProgramName,
pgmconfig.PluginRoot,
"builtin",
plugins.BuiltinPluginPackage,
root+".go")
}

Expand Down
25 changes: 25 additions & 0 deletions cmd/pluginator/plugintype_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/accumulator/resaccumulator.go
Expand Up @@ -135,7 +135,7 @@ func (ra *ResAccumulator) makeVarReplacementMap() (map[string]interface{}, error
return result, nil
}

func (ra *ResAccumulator) Transform(t transformers.Transformer) error {
func (ra *ResAccumulator) Transform(t resmap.Transformer) error {
return t.Transform(ra.resMap)
}

Expand Down
37 changes: 37 additions & 0 deletions pkg/plugins/builtinplugintype_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 75 additions & 0 deletions pkg/plugins/builtins.go
@@ -0,0 +1,75 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package plugins

import (
"sigs.k8s.io/kustomize/v3/pkg/resmap"
"sigs.k8s.io/kustomize/v3/plugin/builtin"
)

//go:generate stringer -type=BuiltinPluginType
type BuiltinPluginType int

const (
Unknown BuiltinPluginType = iota
SecretGenerator
ConfigMapGenerator
ReplicaCountTransformer
NamespaceTransformer
PatchJson6902Transformer
PatchStrategicMergeTransformer
PatchTransformer
LabelTransformer
AnnotationsTransformer
PrefixSuffixTransformer
ImageTagTransformer
HashTransformer
InventoryTransformer
LegacyOrderTransformer
)

var stringToBuiltinPluginTypeMap map[string]BuiltinPluginType

func init() {
stringToBuiltinPluginTypeMap = makeStringToBuiltinPluginTypeMap()
}

func makeStringToBuiltinPluginTypeMap() (result map[string]BuiltinPluginType) {
result = make(map[string]BuiltinPluginType, 23)
for k := range GeneratorFactories {
result[k.String()] = k
}
for k := range TransformerFactories {
result[k.String()] = k
}
return
}

func GetBuiltinPluginType(n string) BuiltinPluginType {
result, ok := stringToBuiltinPluginTypeMap[n]
if ok {
return result
}
return Unknown
}

var GeneratorFactories = map[BuiltinPluginType]func() resmap.GeneratorPlugin{
SecretGenerator: builtin.NewSecretGeneratorPlugin,
ConfigMapGenerator: builtin.NewConfigMapGeneratorPlugin,
}

var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin{
NamespaceTransformer: builtin.NewNamespaceTransformerPlugin,
ReplicaCountTransformer: builtin.NewReplicaCountTransformerPlugin,
PatchJson6902Transformer: builtin.NewPatchJson6902TransformerPlugin,
PatchStrategicMergeTransformer: builtin.NewPatchStrategicMergeTransformerPlugin,
PatchTransformer: builtin.NewPatchTransformerPlugin,
LabelTransformer: builtin.NewLabelTransformerPlugin,
AnnotationsTransformer: builtin.NewAnnotationsTransformerPlugin,
PrefixSuffixTransformer: builtin.NewPrefixSuffixTransformerPlugin,
ImageTagTransformer: builtin.NewImageTagTransformerPlugin,
HashTransformer: builtin.NewHashTransformerPlugin,
InventoryTransformer: builtin.NewInventoryTransformerPlugin,
LegacyOrderTransformer: builtin.NewLegacyOrderTransformerPlugin,
}
10 changes: 6 additions & 4 deletions pkg/plugins/config.go
Expand Up @@ -12,13 +12,15 @@ import (
)

const (
PluginSymbol = "KustomizePlugin"
flagEnablePluginsName = "enable_alpha_plugins"
flagEnablePluginsHelp = `enable plugins, an alpha feature.
PluginSymbol = "KustomizePlugin"
BuiltinPluginPackage = "builtin"
BuiltinPluginApiVersion = BuiltinPluginPackage
flagEnablePluginsName = "enable_alpha_plugins"
flagEnablePluginsHelp = `enable plugins, an alpha feature.
See https://github.com/kubernetes-sigs/kustomize/blob/master/docs/plugins.md
`
flagErrorFmt = `
unable to load plugin %s because plugins disabled
unable to load external plugin %s because plugins disabled
specify the flag
--%s
to %s`
Expand Down
67 changes: 43 additions & 24 deletions pkg/plugins/loader.go
Expand Up @@ -11,18 +11,14 @@ import (
"strings"

"github.com/pkg/errors"
"sigs.k8s.io/kustomize/v3/pkg/gvk"
"sigs.k8s.io/kustomize/v3/pkg/ifc"
"sigs.k8s.io/kustomize/v3/pkg/resid"
"sigs.k8s.io/kustomize/v3/pkg/resmap"
"sigs.k8s.io/kustomize/v3/pkg/resource"
"sigs.k8s.io/kustomize/v3/pkg/transformers"
"sigs.k8s.io/kustomize/v3/pkg/types"
)

type Configurable interface {
Config(ldr ifc.Loader, rf *resmap.Factory, config []byte) error
}

type Loader struct {
pc *types.PluginConfig
rf *resmap.Factory
Expand All @@ -34,8 +30,8 @@ func NewLoader(
}

func (l *Loader) LoadGenerators(
ldr ifc.Loader, rm resmap.ResMap) ([]transformers.Generator, error) {
var result []transformers.Generator
ldr ifc.Loader, rm resmap.ResMap) ([]resmap.Generator, error) {
var result []resmap.Generator
for _, res := range rm.Resources() {
g, err := l.LoadGenerator(ldr, res)
if err != nil {
Expand All @@ -47,21 +43,21 @@ func (l *Loader) LoadGenerators(
}

func (l *Loader) LoadGenerator(
ldr ifc.Loader, res *resource.Resource) (transformers.Generator, error) {
ldr ifc.Loader, res *resource.Resource) (resmap.Generator, error) {
c, err := l.loadAndConfigurePlugin(ldr, res)
if err != nil {
return nil, err
}
g, ok := c.(transformers.Generator)
g, ok := c.(resmap.Generator)
if !ok {
return nil, fmt.Errorf("plugin %s not a generator", res.OrgId())
}
return g, nil
}

func (l *Loader) LoadTransformers(
ldr ifc.Loader, rm resmap.ResMap) ([]transformers.Transformer, error) {
var result []transformers.Transformer
ldr ifc.Loader, rm resmap.ResMap) ([]resmap.Transformer, error) {
var result []resmap.Transformer
for _, res := range rm.Resources() {
t, err := l.LoadTransformer(ldr, res)
if err != nil {
Expand All @@ -73,12 +69,12 @@ func (l *Loader) LoadTransformers(
}

func (l *Loader) LoadTransformer(
ldr ifc.Loader, res *resource.Resource) (transformers.Transformer, error) {
ldr ifc.Loader, res *resource.Resource) (resmap.Transformer, error) {
c, err := l.loadAndConfigurePlugin(ldr, res)
if err != nil {
return nil, err
}
t, ok := c.(transformers.Transformer)
t, ok := c.(resmap.Transformer)
if !ok {
return nil, fmt.Errorf("plugin %s not a transformer", res.OrgId())
}
Expand All @@ -101,13 +97,25 @@ func (l *Loader) absolutePluginPath(id resid.ResId) string {
return AbsolutePluginPath(l.pc, id)
}

// TODO: https://github.com/kubernetes-sigs/kustomize/issues/1164
func isBuiltinPlugin(res *resource.Resource) bool {
// TODO: the special string should appear in Group, not Version.
return res.GetGvk().Group == "" &&
res.GetGvk().Version == BuiltinPluginApiVersion
}

func (l *Loader) loadAndConfigurePlugin(
ldr ifc.Loader, res *resource.Resource) (Configurable, error) {
if !l.pc.Enabled {
return nil, NotEnabledErr(res.OrgId().Kind)
ldr ifc.Loader, res *resource.Resource) (c resmap.Configurable, err error) {
if isBuiltinPlugin(res) {
// Instead of looking for and loading a .so file, just
// instantiate the plugin from a generated factory
// function (see "pluginator"). Being able to do this
// is what makes a plugin "builtin".
c, err = l.makeBuiltinPlugin(res.GetGvk())
} else if l.pc.Enabled {
c, err = l.loadPlugin(res.OrgId())
} else {
err = NotEnabledErr(res.OrgId().Kind)
}
c, err := l.loadPlugin(res.OrgId())
if err != nil {
return nil, err
}
Expand All @@ -123,7 +131,18 @@ func (l *Loader) loadAndConfigurePlugin(
return c, nil
}

func (l *Loader) loadPlugin(resId resid.ResId) (Configurable, error) {
func (l *Loader) makeBuiltinPlugin(r gvk.Gvk) (resmap.Configurable, error) {
bpt := GetBuiltinPluginType(r.Kind)
if f, ok := GeneratorFactories[bpt]; ok {
return f(), nil
}
if f, ok := TransformerFactories[bpt]; ok {
return f(), nil
}
return nil, errors.Errorf("unable to load builtin %s", r)
}

func (l *Loader) loadPlugin(resId resid.ResId) (resmap.Configurable, error) {
p := NewExecPlugin(l.absolutePluginPath(resId))
if p.isAvailable() {
return p, nil
Expand All @@ -141,9 +160,9 @@ func (l *Loader) loadPlugin(resId resid.ResId) (Configurable, error) {
// but the loaded .so files are in shared memory, so one will get
// "this plugin already loaded" errors if the registry is maintained
// as a Loader instance variable. So make it a package variable.
var registry = make(map[string]Configurable)
var registry = make(map[string]resmap.Configurable)

func (l *Loader) loadGoPlugin(id resid.ResId) (Configurable, error) {
func (l *Loader) loadGoPlugin(id resid.ResId) (resmap.Configurable, error) {
regId := relativePluginPath(id)
if c, ok := registry[regId]; ok {
return copyPlugin(c), nil
Expand All @@ -159,18 +178,18 @@ func (l *Loader) loadGoPlugin(id resid.ResId) (Configurable, error) {
err, "plugin %s doesn't have symbol %s",
regId, PluginSymbol)
}
c, ok := symbol.(Configurable)
c, ok := symbol.(resmap.Configurable)
if !ok {
return nil, fmt.Errorf("plugin %s not configurable", regId)
}
registry[regId] = c
return copyPlugin(c), nil
}

func copyPlugin(c Configurable) Configurable {
func copyPlugin(c resmap.Configurable) resmap.Configurable {
indirect := reflect.Indirect(reflect.ValueOf(c))
newIndirect := reflect.New(indirect.Type())
newIndirect.Elem().Set(reflect.ValueOf(indirect.Interface()))
newNamed := newIndirect.Interface()
return newNamed.(Configurable)
return newNamed.(resmap.Configurable)
}

0 comments on commit 2050afd

Please sign in to comment.