mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-10 08:20:59 +00:00
Merge pull request #1532 from monopole/runBuiltinSansFlag
Ease configuring and running the builtin plugins.
This commit is contained in:
@@ -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")
|
||||
@@ -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 l == "var "+plugins.PluginSymbol+" plugin" {
|
||||
w.write("func New" + root + "Plugin() *" + root + "Plugin {")
|
||||
w.write(" return &" + root + "Plugin{}")
|
||||
w.write("}")
|
||||
if strings.HasPrefix(l, "//noinspection") {
|
||||
continue
|
||||
}
|
||||
if l == "var "+plugins.PluginSymbol+" plugin" {
|
||||
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 {
|
||||
@@ -93,7 +119,7 @@ func makeOutputFileName(root string) string {
|
||||
pgmconfig.DomainName,
|
||||
pgmconfig.ProgramName,
|
||||
pgmconfig.PluginRoot,
|
||||
"builtin",
|
||||
plugins.BuiltinPluginPackage,
|
||||
root+".go")
|
||||
}
|
||||
|
||||
|
||||
25
cmd/pluginator/plugintype_string.go
Normal file
25
cmd/pluginator/plugintype_string.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Code generated by "stringer -type=pluginType"; DO NOT EDIT.
|
||||
|
||||
package main
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[unknown-0]
|
||||
_ = x[Transformer-1]
|
||||
_ = x[Generator-2]
|
||||
}
|
||||
|
||||
const _pluginType_name = "unknownTransformerGenerator"
|
||||
|
||||
var _pluginType_index = [...]uint8{0, 7, 18, 27}
|
||||
|
||||
func (i pluginType) String() string {
|
||||
if i < 0 || i >= pluginType(len(_pluginType_index)-1) {
|
||||
return "pluginType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _pluginType_name[_pluginType_index[i]:_pluginType_index[i+1]]
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
37
pkg/plugins/builtinplugintype_string.go
Normal file
37
pkg/plugins/builtinplugintype_string.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Code generated by "stringer -type=BuiltinPluginType"; DO NOT EDIT.
|
||||
|
||||
package plugins
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Unknown-0]
|
||||
_ = x[SecretGenerator-1]
|
||||
_ = x[ConfigMapGenerator-2]
|
||||
_ = x[ReplicaCountTransformer-3]
|
||||
_ = x[NamespaceTransformer-4]
|
||||
_ = x[PatchJson6902Transformer-5]
|
||||
_ = x[PatchStrategicMergeTransformer-6]
|
||||
_ = x[PatchTransformer-7]
|
||||
_ = x[LabelTransformer-8]
|
||||
_ = x[AnnotationsTransformer-9]
|
||||
_ = x[PrefixSuffixTransformer-10]
|
||||
_ = x[ImageTagTransformer-11]
|
||||
_ = x[HashTransformer-12]
|
||||
_ = x[InventoryTransformer-13]
|
||||
_ = x[LegacyOrderTransformer-14]
|
||||
}
|
||||
|
||||
const _BuiltinPluginType_name = "UnknownSecretGeneratorConfigMapGeneratorReplicaCountTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerLabelTransformerAnnotationsTransformerPrefixSuffixTransformerImageTagTransformerHashTransformerInventoryTransformerLegacyOrderTransformer"
|
||||
|
||||
var _BuiltinPluginType_index = [...]uint16{0, 7, 22, 40, 63, 83, 107, 137, 153, 169, 191, 214, 233, 248, 268, 290}
|
||||
|
||||
func (i BuiltinPluginType) String() string {
|
||||
if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) {
|
||||
return "BuiltinPluginType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _BuiltinPluginType_name[_BuiltinPluginType_index[i]:_BuiltinPluginType_index[i+1]]
|
||||
}
|
||||
75
pkg/plugins/builtins.go
Normal file
75
pkg/plugins/builtins.go
Normal file
@@ -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,
|
||||
}
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
@@ -47,12 +43,12 @@ 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())
|
||||
}
|
||||
@@ -60,8 +56,8 @@ func (l *Loader) LoadGenerator(
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -159,7 +178,7 @@ 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)
|
||||
}
|
||||
@@ -167,10 +186,10 @@ func (l *Loader) loadGoPlugin(id resid.ResId) (Configurable, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -11,13 +11,45 @@ import (
|
||||
"regexp"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// A Transformer modifies an instance of ResMap.
|
||||
type Transformer interface {
|
||||
// Transform modifies data in the argument,
|
||||
// e.g. adding labels to resources that can be labelled.
|
||||
Transform(m ResMap) error
|
||||
}
|
||||
|
||||
// A Generator creates an instance of ResMap.
|
||||
type Generator interface {
|
||||
Generate() (ResMap, error)
|
||||
}
|
||||
|
||||
// Something that's configurable accepts a config
|
||||
// object (typically YAML in []byte form), and an
|
||||
// ifc.Loader to possible read more configuration
|
||||
// from the file system (e.g. patch files) and
|
||||
// a resource factory to build any type-sensitive
|
||||
// parts. The factory could probably be factored out.
|
||||
type Configurable interface {
|
||||
Config(ldr ifc.Loader, rf *Factory, config []byte) error
|
||||
}
|
||||
|
||||
type GeneratorPlugin interface {
|
||||
Generator
|
||||
Configurable
|
||||
}
|
||||
|
||||
type TransformerPlugin interface {
|
||||
Transformer
|
||||
Configurable
|
||||
}
|
||||
|
||||
// ResMap is an interface describing operations on the
|
||||
// core kustomize data structure, a list of Resources.
|
||||
//
|
||||
|
||||
@@ -160,7 +160,7 @@ func (kt *KustTarget) makeCustomizedResMap(
|
||||
func (kt *KustTarget) addHashesToNames(
|
||||
ra *accumulator.ResAccumulator) error {
|
||||
p := builtin.NewHashTransformerPlugin()
|
||||
err := kt.configureBuiltinPlugin(p, nil, "hash")
|
||||
err := kt.configureBuiltinPlugin(p, nil, plugins.HashTransformer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -181,7 +181,6 @@ func (kt *KustTarget) computeInventory(
|
||||
return fmt.Errorf("namespace mismatch")
|
||||
}
|
||||
|
||||
p := builtin.NewInventoryTransformerPlugin()
|
||||
var c struct {
|
||||
Policy string
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
@@ -189,8 +188,8 @@ func (kt *KustTarget) computeInventory(
|
||||
c.Name = inv.ConfigMap.Name
|
||||
c.Namespace = inv.ConfigMap.Namespace
|
||||
c.Policy = garbagePolicy.String()
|
||||
|
||||
err := kt.configureBuiltinPlugin(p, c, "inventory")
|
||||
p := builtin.NewInventoryTransformerPlugin()
|
||||
err := kt.configureBuiltinPlugin(p, c, plugins.InventoryTransformer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -283,7 +282,7 @@ func (kt *KustTarget) runGenerators(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureExternalGenerators() ([]transformers.Generator, error) {
|
||||
func (kt *KustTarget) configureExternalGenerators() ([]resmap.Generator, error) {
|
||||
ra := accumulator.MakeEmptyAccumulator()
|
||||
err := kt.accumulateResources(ra, kt.kustomization.Generators)
|
||||
if err != nil {
|
||||
@@ -293,7 +292,7 @@ func (kt *KustTarget) configureExternalGenerators() ([]transformers.Generator, e
|
||||
}
|
||||
|
||||
func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
|
||||
var r []transformers.Transformer
|
||||
var r []resmap.Transformer
|
||||
tConfig := ra.GetTransformerConfig()
|
||||
lts, err := kt.configureBuiltinTransformers(tConfig)
|
||||
if err != nil {
|
||||
@@ -309,7 +308,7 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
|
||||
return ra.Transform(t)
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureExternalTransformers() ([]transformers.Transformer, error) {
|
||||
func (kt *KustTarget) configureExternalTransformers() ([]resmap.Transformer, error) {
|
||||
ra := accumulator.MakeEmptyAccumulator()
|
||||
err := kt.accumulateResources(ra, kt.kustomization.Transformers)
|
||||
if err != nil {
|
||||
@@ -374,3 +373,20 @@ func (kt *KustTarget) accumulateFile(
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinPlugin(
|
||||
p resmap.Configurable, c interface{}, bpt plugins.BuiltinPluginType) (err error) {
|
||||
var y []byte
|
||||
if c != nil {
|
||||
y, err = yaml.Marshal(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(
|
||||
err, "builtin %s marshal", bpt)
|
||||
}
|
||||
}
|
||||
err = p.Config(kt.ldr, kt.rFactory, y)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "builtin %s config: %v", bpt, y)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,50 +4,36 @@
|
||||
package target
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/image"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/transformers/config"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||
"sigs.k8s.io/kustomize/v3/plugin/builtin"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Functions dedicated to configuring the builtin
|
||||
// transformer and generator plugins using config data
|
||||
// read from a kustomization file.
|
||||
// read from a kustomization file and from the
|
||||
// config.TransformerConfig, whose data may be a
|
||||
// mix of hardcoded values and data read from file.
|
||||
//
|
||||
// Non-builtin plugins will get their configuration
|
||||
// from their own dedicated structs and yaml files.
|
||||
// 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
|
||||
// the kustomization file would, say, allow someone 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)
|
||||
// image tag transforms. In these cases, we'll need
|
||||
// N plugin instances with differing configurations.
|
||||
|
||||
func (kt *KustTarget) configureBuiltinGenerators() (
|
||||
[]transformers.Generator, error) {
|
||||
configurators := []generatorConfigurator{
|
||||
kt.configureBuiltinConfigMapGenerator,
|
||||
kt.configureBuiltinSecretGenerator,
|
||||
}
|
||||
var result []transformers.Generator
|
||||
for _, f := range configurators {
|
||||
r, err := f()
|
||||
result []resmap.Generator, err error) {
|
||||
for _, bpt := range []plugins.BuiltinPluginType{
|
||||
plugins.ConfigMapGenerator,
|
||||
plugins.SecretGenerator,
|
||||
} {
|
||||
r, err := generatorConfigurators[bpt](
|
||||
kt, bpt, plugins.GeneratorFactories[bpt])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -57,270 +43,256 @@ func (kt *KustTarget) configureBuiltinGenerators() (
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinTransformers(
|
||||
tConfig *config.TransformerConfig) (
|
||||
[]transformers.Transformer, error) {
|
||||
// TODO: Convert remaining legacy transformers to plugins
|
||||
// with tests:
|
||||
// - patch SMP
|
||||
configurators := []transformerConfigurator{
|
||||
kt.configureBuiltinPatchStrategicMergeTransformer,
|
||||
kt.configureBuiltinPatchTransformer,
|
||||
kt.configureBuiltinNamespaceTransformer,
|
||||
kt.configureBuiltinNameTransformer,
|
||||
kt.configureBuiltinLabelTransformer,
|
||||
kt.configureBuiltinAnnotationsTransformer,
|
||||
kt.configureBuiltinPatchJson6902Transformer,
|
||||
kt.configureBuiltinReplicaCountTransformer,
|
||||
kt.configureBuiltinImageTagTransformer,
|
||||
}
|
||||
var result []transformers.Transformer
|
||||
for _, f := range configurators {
|
||||
r, err := f(tConfig)
|
||||
tc *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
for _, bpt := range []plugins.BuiltinPluginType{
|
||||
plugins.PatchStrategicMergeTransformer,
|
||||
plugins.PatchTransformer,
|
||||
plugins.NamespaceTransformer,
|
||||
plugins.PrefixSuffixTransformer,
|
||||
plugins.LabelTransformer,
|
||||
plugins.AnnotationsTransformer,
|
||||
plugins.PatchJson6902Transformer,
|
||||
plugins.ReplicaCountTransformer,
|
||||
plugins.ImageTagTransformer,
|
||||
} {
|
||||
r, err := transformerConfigurators[bpt](
|
||||
kt, bpt, plugins.TransformerFactories[bpt], tc)
|
||||
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 := builtin.NewSecretGeneratorPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "secret")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
type gFactory func() resmap.GeneratorPlugin
|
||||
|
||||
var generatorConfigurators = map[plugins.BuiltinPluginType]func(
|
||||
kt *KustTarget,
|
||||
bpt plugins.BuiltinPluginType,
|
||||
factory gFactory) (result []resmap.Generator, err error){
|
||||
plugins.SecretGenerator: func(kt *KustTarget, bpt plugins.BuiltinPluginType, f gFactory) (
|
||||
result []resmap.Generator, err error) {
|
||||
var c struct {
|
||||
types.GeneratorOptions
|
||||
types.SecretArgs
|
||||
}
|
||||
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 := builtin.NewConfigMapGeneratorPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "configmap")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if kt.kustomization.GeneratorOptions != nil {
|
||||
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinNamespaceTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
var c struct {
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
c.Namespace = kt.kustomization.Namespace
|
||||
c.FieldSpecs = tConfig.NameSpace
|
||||
p := builtin.NewNamespaceTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "namespace")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinPatchJson6902Transformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
var c struct {
|
||||
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
}
|
||||
for _, args := range kt.kustomization.PatchesJson6902 {
|
||||
c.Target = *args.Target
|
||||
c.Path = args.Path
|
||||
c.JsonOp = args.Patch
|
||||
p := builtin.NewPatchJson6902TransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "patchJson6902")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, args := range kt.kustomization.SecretGenerator {
|
||||
c.SecretArgs = args
|
||||
p := f()
|
||||
err := kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinPatchStrategicMergeTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
if len(kt.kustomization.PatchesStrategicMerge) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
}
|
||||
c.Paths = kt.kustomization.PatchesStrategicMerge
|
||||
p := builtin.NewPatchStrategicMergeTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "patchStrategicMerge")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
}
|
||||
},
|
||||
|
||||
func (kt *KustTarget) configureBuiltinPatchTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
if len(kt.kustomization.Patches) == 0 {
|
||||
plugins.ConfigMapGenerator: func(kt *KustTarget, bpt plugins.BuiltinPluginType, f gFactory) (
|
||||
result []resmap.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 := f()
|
||||
err := kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
}
|
||||
for _, patch := range kt.kustomization.Patches {
|
||||
c.Target = patch.Target
|
||||
c.Patch = patch.Patch
|
||||
c.Path = patch.Path
|
||||
p := builtin.NewPatchTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "patch")
|
||||
},
|
||||
}
|
||||
|
||||
type tFactory func() resmap.TransformerPlugin
|
||||
|
||||
var transformerConfigurators = map[plugins.BuiltinPluginType]func(
|
||||
kt *KustTarget,
|
||||
bpt plugins.BuiltinPluginType,
|
||||
f tFactory,
|
||||
tc *config.TransformerConfig) (result []resmap.Transformer, err error){
|
||||
plugins.NamespaceTransformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, tc *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
c.Namespace = kt.kustomization.Namespace
|
||||
c.FieldSpecs = tc.NameSpace
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
},
|
||||
|
||||
func (kt *KustTarget) configureBuiltinLabelTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
var c struct {
|
||||
Labels map[string]string
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
c.Labels = kt.kustomization.CommonLabels
|
||||
c.FieldSpecs = tConfig.CommonLabels
|
||||
p := builtin.NewLabelTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "label")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinAnnotationsTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
var c struct {
|
||||
Annotations map[string]string
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
c.Annotations = kt.kustomization.CommonAnnotations
|
||||
c.FieldSpecs = tConfig.CommonAnnotations
|
||||
p := builtin.NewAnnotationsTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "annotations")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinNameTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
var c struct {
|
||||
Prefix string
|
||||
Suffix string
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
c.Prefix = kt.kustomization.NamePrefix
|
||||
c.Suffix = kt.kustomization.NameSuffix
|
||||
c.FieldSpecs = tConfig.NamePrefix
|
||||
p := builtin.NewPrefixSuffixTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "prefixsuffix")
|
||||
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 := builtin.NewImageTagTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "imageTag")
|
||||
plugins.PatchJson6902Transformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, _ *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
}
|
||||
for _, args := range kt.kustomization.PatchesJson6902 {
|
||||
c.Target = *args.Target
|
||||
c.Path = args.Path
|
||||
c.JsonOp = args.Patch
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
plugins.PatchStrategicMergeTransformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, _ *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.PatchesStrategicMerge) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
}
|
||||
c.Paths = kt.kustomization.PatchesStrategicMerge
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinReplicaCountTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
var c struct {
|
||||
Replica types.Replica
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
for _, args := range kt.kustomization.Replicas {
|
||||
c.Replica = args
|
||||
c.FieldSpecs = tConfig.Replicas
|
||||
p := builtin.NewReplicaCountTransformerPlugin()
|
||||
err = kt.configureBuiltinPlugin(p, c, "replica")
|
||||
return
|
||||
},
|
||||
plugins.PatchTransformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, _ *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.Patches) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
}
|
||||
for _, pc := range kt.kustomization.Patches {
|
||||
c.Target = pc.Target
|
||||
c.Patch = pc.Patch
|
||||
c.Path = pc.Path
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
plugins.LabelTransformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, tc *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Labels map[string]string
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
c.Labels = kt.kustomization.CommonLabels
|
||||
c.FieldSpecs = tc.CommonLabels
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinPlugin(
|
||||
p plugins.Configurable, c interface{}, id string) (err error) {
|
||||
var y []byte
|
||||
if c != nil {
|
||||
y, err = yaml.Marshal(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(
|
||||
err, "builtin %s marshal", id)
|
||||
return
|
||||
},
|
||||
plugins.AnnotationsTransformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, tc *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Annotations map[string]string
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
}
|
||||
err = p.Config(kt.ldr, kt.rFactory, y)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "builtin %s config: %v", id, y)
|
||||
}
|
||||
return nil
|
||||
c.Annotations = kt.kustomization.CommonAnnotations
|
||||
c.FieldSpecs = tc.CommonAnnotations
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
plugins.PrefixSuffixTransformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, tc *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Prefix string
|
||||
Suffix string
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
c.Prefix = kt.kustomization.NamePrefix
|
||||
c.Suffix = kt.kustomization.NameSuffix
|
||||
c.FieldSpecs = tc.NamePrefix
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
plugins.ImageTagTransformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, tc *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
ImageTag image.Image
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
for _, args := range kt.kustomization.Images {
|
||||
c.ImageTag = args
|
||||
c.FieldSpecs = tc.Images
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
plugins.ReplicaCountTransformer: func(
|
||||
kt *KustTarget, bpt plugins.BuiltinPluginType, f tFactory, tc *config.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Replica types.Replica
|
||||
FieldSpecs []config.FieldSpec
|
||||
}
|
||||
for _, args := range kt.kustomization.Replicas {
|
||||
c.Replica = args
|
||||
c.FieldSpecs = tc.Replicas
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ transformers:
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "unable to load plugin StringPrefixer") {
|
||||
if !strings.Contains(err.Error(), "unable to load external plugin StringPrefixer") {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
9
pkg/transformers/doc.go
Normal file
9
pkg/transformers/doc.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Utilities to aid transformer plugins.
|
||||
//
|
||||
// TODO: Push remaining code down into the plugins
|
||||
// or into an appropriately named utility package.
|
||||
// This package made more sense in the pre-plugin days.
|
||||
package transformers
|
||||
@@ -30,23 +30,23 @@ type mapTransformer struct {
|
||||
fieldSpecs []config.FieldSpec
|
||||
}
|
||||
|
||||
var _ Transformer = &mapTransformer{}
|
||||
var _ resmap.Transformer = &mapTransformer{}
|
||||
|
||||
// NewLabelsMapTransformer constructs a mapTransformer.
|
||||
func NewLabelsMapTransformer(
|
||||
m map[string]string, fs []config.FieldSpec) (Transformer, error) {
|
||||
m map[string]string, fs []config.FieldSpec) (resmap.Transformer, error) {
|
||||
return NewMapTransformer(fs, m)
|
||||
}
|
||||
|
||||
// NewAnnotationsMapTransformer construct a mapTransformer.
|
||||
func NewAnnotationsMapTransformer(
|
||||
m map[string]string, fs []config.FieldSpec) (Transformer, error) {
|
||||
m map[string]string, fs []config.FieldSpec) (resmap.Transformer, error) {
|
||||
return NewMapTransformer(fs, m)
|
||||
}
|
||||
|
||||
// NewMapTransformer construct a mapTransformer.
|
||||
func NewMapTransformer(
|
||||
pc []config.FieldSpec, m map[string]string) (Transformer, error) {
|
||||
pc []config.FieldSpec, m map[string]string) (resmap.Transformer, error) {
|
||||
if m == nil {
|
||||
return NewNoOpTransformer(), nil
|
||||
}
|
||||
|
||||
@@ -24,25 +24,25 @@ import (
|
||||
|
||||
// multiTransformer contains a list of transformers.
|
||||
type multiTransformer struct {
|
||||
transformers []Transformer
|
||||
transformers []resmap.Transformer
|
||||
checkConflictEnabled bool
|
||||
}
|
||||
|
||||
var _ Transformer = &multiTransformer{}
|
||||
var _ resmap.Transformer = &multiTransformer{}
|
||||
|
||||
// NewMultiTransformer constructs a multiTransformer.
|
||||
func NewMultiTransformer(t []Transformer) Transformer {
|
||||
func NewMultiTransformer(t []resmap.Transformer) resmap.Transformer {
|
||||
r := &multiTransformer{
|
||||
transformers: make([]Transformer, len(t)),
|
||||
transformers: make([]resmap.Transformer, len(t)),
|
||||
checkConflictEnabled: false}
|
||||
copy(r.transformers, t)
|
||||
return r
|
||||
}
|
||||
|
||||
// NewMultiTransformerWithConflictCheck constructs a multiTransformer with checking of conflicts.
|
||||
func NewMultiTransformerWithConflictCheck(t []Transformer) Transformer {
|
||||
func NewMultiTransformerWithConflictCheck(t []resmap.Transformer) resmap.Transformer {
|
||||
r := &multiTransformer{
|
||||
transformers: make([]Transformer, len(t)),
|
||||
transformers: make([]resmap.Transformer, len(t)),
|
||||
checkConflictEnabled: true}
|
||||
copy(r.transformers, t)
|
||||
return r
|
||||
|
||||
@@ -18,11 +18,11 @@ type nameReferenceTransformer struct {
|
||||
backRefs []config.NameBackReferences
|
||||
}
|
||||
|
||||
var _ Transformer = &nameReferenceTransformer{}
|
||||
var _ resmap.Transformer = &nameReferenceTransformer{}
|
||||
|
||||
// NewNameReferenceTransformer constructs a nameReferenceTransformer
|
||||
// with a given slice of NameBackReferences.
|
||||
func NewNameReferenceTransformer(br []config.NameBackReferences) Transformer {
|
||||
func NewNameReferenceTransformer(br []config.NameBackReferences) resmap.Transformer {
|
||||
if br == nil {
|
||||
log.Fatal("backrefs not expected to be nil")
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ import "sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||
// noOpTransformer contains a no-op transformer.
|
||||
type noOpTransformer struct{}
|
||||
|
||||
var _ Transformer = &noOpTransformer{}
|
||||
var _ resmap.Transformer = &noOpTransformer{}
|
||||
|
||||
// NewNoOpTransformer constructs a noOpTransformer.
|
||||
func NewNoOpTransformer() Transformer {
|
||||
func NewNoOpTransformer() resmap.Transformer {
|
||||
return &noOpTransformer{}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
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 transformers has implementations of resmap.ResMap transformers.
|
||||
package transformers
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||
)
|
||||
|
||||
// A Transformer modifies an instance of resmap.ResMap.
|
||||
type Transformer interface {
|
||||
// Transform modifies data in the argument, e.g. adding labels to resources that can be labelled.
|
||||
Transform(m resmap.ResMap) error
|
||||
}
|
||||
|
||||
// A Generator creates an instance of resmap.ResMap.
|
||||
type Generator interface {
|
||||
Generate() (resmap.ResMap, error)
|
||||
}
|
||||
@@ -15,11 +15,6 @@ type AnnotationsTransformerPlugin struct {
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewAnnotationsTransformerPlugin() *AnnotationsTransformerPlugin {
|
||||
return &AnnotationsTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *AnnotationsTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.Annotations = nil
|
||||
@@ -37,3 +32,7 @@ func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
}
|
||||
return t.Transform(m)
|
||||
}
|
||||
|
||||
func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &AnnotationsTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,6 @@ type ConfigMapGeneratorPlugin struct {
|
||||
types.ConfigMapArgs
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewConfigMapGeneratorPlugin() *ConfigMapGeneratorPlugin {
|
||||
return &ConfigMapGeneratorPlugin{}
|
||||
}
|
||||
|
||||
func (p *ConfigMapGeneratorPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.GeneratorOptions = types.GeneratorOptions{}
|
||||
@@ -40,3 +35,7 @@ func (p *ConfigMapGeneratorPlugin) Config(
|
||||
func (p *ConfigMapGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
return p.rf.FromConfigMapArgs(p.ldr, &p.GeneratorOptions, p.ConfigMapArgs)
|
||||
}
|
||||
|
||||
func NewConfigMapGeneratorPlugin() resmap.GeneratorPlugin {
|
||||
return &ConfigMapGeneratorPlugin{}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,6 @@ type HashTransformerPlugin struct {
|
||||
hasher ifc.KunstructuredHasher
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewHashTransformerPlugin() *HashTransformerPlugin {
|
||||
return &HashTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *HashTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.hasher = rf.RF().Hasher()
|
||||
@@ -36,3 +31,7 @@ func (p *HashTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHashTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &HashTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,6 @@ type ImageTagTransformerPlugin struct {
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewImageTagTransformerPlugin() *ImageTagTransformerPlugin {
|
||||
return &ImageTagTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *ImageTagTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.ImageTag = image.Image{}
|
||||
@@ -183,3 +178,7 @@ func split(imageName string) (name string, tag string) {
|
||||
tag = imageName[i:]
|
||||
return
|
||||
}
|
||||
|
||||
func NewImageTagTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &ImageTagTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,6 @@ type InventoryTransformerPlugin struct {
|
||||
Policy string `json:"policy,omitempty" yaml:"policy,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewInventoryTransformerPlugin() *InventoryTransformerPlugin {
|
||||
return &InventoryTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *InventoryTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.ldr = ldr
|
||||
@@ -127,3 +122,7 @@ func computeRefs(
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NewInventoryTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &InventoryTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,6 @@ type LabelTransformerPlugin struct {
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewLabelTransformerPlugin() *LabelTransformerPlugin {
|
||||
return &LabelTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *LabelTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.Labels = nil
|
||||
@@ -37,3 +32,7 @@ func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
}
|
||||
return t.Transform(m)
|
||||
}
|
||||
|
||||
func NewLabelTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &LabelTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,6 @@ import (
|
||||
// (like ValidatingWebhookConfiguration) last.
|
||||
type LegacyOrderTransformerPlugin struct{}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewLegacyOrderTransformerPlugin() *LegacyOrderTransformerPlugin {
|
||||
return &LegacyOrderTransformerPlugin{}
|
||||
}
|
||||
|
||||
// Nothing needed for configuration.
|
||||
func (p *LegacyOrderTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
@@ -43,3 +38,7 @@ func (p *LegacyOrderTransformerPlugin) Transform(m resmap.ResMap) (err error) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewLegacyOrderTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &LegacyOrderTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,6 @@ type NamespaceTransformerPlugin struct {
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewNamespaceTransformerPlugin() *NamespaceTransformerPlugin {
|
||||
return &NamespaceTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *NamespaceTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.Namespace = ""
|
||||
@@ -129,3 +124,7 @@ func (o *NamespaceTransformerPlugin) changeNamespace(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewNamespaceTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &NamespaceTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,6 @@ type PatchJson6902TransformerPlugin struct {
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewPatchJson6902TransformerPlugin() *PatchJson6902TransformerPlugin {
|
||||
return &PatchJson6902TransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *PatchJson6902TransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.ldr = ldr
|
||||
@@ -97,3 +92,7 @@ func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
}
|
||||
return obj.UnmarshalJSON(modifiedObj)
|
||||
}
|
||||
|
||||
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {
|
||||
return &PatchJson6902TransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,6 @@ type PatchStrategicMergeTransformerPlugin struct {
|
||||
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewPatchStrategicMergeTransformerPlugin() *PatchStrategicMergeTransformerPlugin {
|
||||
return &PatchStrategicMergeTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *PatchStrategicMergeTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.ldr = ldr
|
||||
@@ -88,3 +83,7 @@ func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewPatchStrategicMergeTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &PatchStrategicMergeTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,6 @@ type PatchTransformerPlugin struct {
|
||||
Target *types.Selector `json:"target,omitempty", yaml:"target,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewPatchTransformerPlugin() *PatchTransformerPlugin {
|
||||
return &PatchTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *PatchTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
p.ldr = ldr
|
||||
@@ -146,3 +141,7 @@ func jsonPatchFromBytes(
|
||||
}
|
||||
return jsonpatch.DecodePatch([]byte(ops))
|
||||
}
|
||||
|
||||
func NewPatchTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &PatchTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,6 @@ type PrefixSuffixTransformerPlugin struct {
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewPrefixSuffixTransformerPlugin() *PrefixSuffixTransformerPlugin {
|
||||
return &PrefixSuffixTransformerPlugin{}
|
||||
}
|
||||
|
||||
// Not placed in a file yet due to lack of demand.
|
||||
var prefixSuffixFieldSpecsToSkip = []config.FieldSpec{
|
||||
{
|
||||
@@ -118,3 +113,7 @@ func (p *PrefixSuffixTransformerPlugin) addPrefixSuffix(
|
||||
}
|
||||
return fmt.Sprintf("%s%s%s", p.Prefix, s, p.Suffix), nil
|
||||
}
|
||||
|
||||
func NewPrefixSuffixTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &PrefixSuffixTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,6 @@ type ReplicaCountTransformerPlugin struct {
|
||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewReplicaCountTransformerPlugin() *ReplicaCountTransformerPlugin {
|
||||
return &ReplicaCountTransformerPlugin{}
|
||||
}
|
||||
|
||||
func (p *ReplicaCountTransformerPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||
|
||||
@@ -88,3 +83,7 @@ func (p *ReplicaCountTransformerPlugin) addReplicas(in interface{}) (interface{}
|
||||
}
|
||||
return p.Replica.Count, nil
|
||||
}
|
||||
|
||||
func NewReplicaCountTransformerPlugin() resmap.TransformerPlugin {
|
||||
return &ReplicaCountTransformerPlugin{}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,6 @@ type SecretGeneratorPlugin struct {
|
||||
types.SecretArgs
|
||||
}
|
||||
|
||||
//noinspection GoUnusedGlobalVariable
|
||||
func NewSecretGeneratorPlugin() *SecretGeneratorPlugin {
|
||||
return &SecretGeneratorPlugin{}
|
||||
}
|
||||
|
||||
func (p *SecretGeneratorPlugin) Config(
|
||||
ldr ifc.Loader, rf *resmap.Factory, config []byte) (err error) {
|
||||
p.GeneratorOptions = types.GeneratorOptions{}
|
||||
@@ -40,3 +35,7 @@ func (p *SecretGeneratorPlugin) Config(
|
||||
func (p *SecretGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||
return p.rf.FromSecretArgs(p.ldr, &p.GeneratorOptions, p.SecretArgs)
|
||||
}
|
||||
|
||||
func NewSecretGeneratorPlugin() resmap.GeneratorPlugin {
|
||||
return &SecretGeneratorPlugin{}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/transformers/config"
|
||||
"sigs.k8s.io/kustomize/v3/plugin/builtin"
|
||||
"sigs.k8s.io/yaml"
|
||||
@@ -16,7 +15,7 @@ import (
|
||||
// Add a date prefix to the name.
|
||||
// A plugin that adapts another plugin.
|
||||
type plugin struct {
|
||||
t transformers.Transformer
|
||||
t resmap.Transformer
|
||||
}
|
||||
|
||||
//nolint: golint
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/transformers/config"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||
"sigs.k8s.io/kustomize/v3/plugin/builtin"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
// A plugin that adapts another plugin.
|
||||
type plugin struct {
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
t transformers.Transformer
|
||||
t resmap.Transformer
|
||||
}
|
||||
|
||||
//nolint: golint
|
||||
|
||||
Reference in New Issue
Block a user