diff --git a/k8sdeps/kunstruct/kunstruct.go b/k8sdeps/kunstruct/kunstruct.go index 5ad306bf5..9fa0b67eb 100644 --- a/k8sdeps/kunstruct/kunstruct.go +++ b/k8sdeps/kunstruct/kunstruct.go @@ -90,3 +90,17 @@ func (fs *UnstructAdapter) GetFieldValue(path string) (string, error) { } return "", fmt.Errorf("no field named '%s'", path) } + +// GetStringSlice returns value at the given fieldpath. +func (fs *UnstructAdapter) GetStringSlice(path string) ([]string, error) { + fields, err := parseFields(path) + if err != nil { + return []string{}, err + } + s, found, err := unstructured.NestedStringSlice( + fs.UnstructuredContent(), fields...) + if found || err != nil { + return s, err + } + return []string{}, fmt.Errorf("no field named '%s'", path) +} diff --git a/pkg/ifc/ifc.go b/pkg/ifc/ifc.go index 3a1815da8..d0251f224 100644 --- a/pkg/ifc/ifc.go +++ b/pkg/ifc/ifc.go @@ -48,6 +48,7 @@ type Kunstructured interface { SetMap(map[string]interface{}) Copy() Kunstructured GetFieldValue(string) (string, error) + GetStringSlice(string) ([]string, error) MarshalJSON() ([]byte, error) UnmarshalJSON([]byte) error GetGvk() gvk.Gvk diff --git a/pkg/plugins/generators.go b/pkg/plugins/generators.go index 45c23e2e8..d40707e44 100644 --- a/pkg/plugins/generators.go +++ b/pkg/plugins/generators.go @@ -18,18 +18,23 @@ package plugins import ( "fmt" + + "sigs.k8s.io/kustomize/pkg/ifc" + "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/transformers" "sigs.k8s.io/kustomize/pkg/types" - - "sigs.k8s.io/kustomize/pkg/resmap" ) type generatorLoader struct { - pc *types.PluginConfig + pc *types.PluginConfig + ldr ifc.Loader + rf *resmap.Factory } -func NewGeneratorLoader(pc *types.PluginConfig) generatorLoader { - return generatorLoader{pc: pc} +func NewGeneratorLoader( + pc *types.PluginConfig, + ldr ifc.Loader, rf *resmap.Factory) generatorLoader { + return generatorLoader{pc: pc, ldr: ldr, rf: rf} } func (l generatorLoader) Load( @@ -43,7 +48,7 @@ func (l generatorLoader) Load( var result []transformers.Generator for id, res := range rm { fileName := pluginFileName(l.pc, id) - c, err := loadAndConfigurePlugin(fileName, res) + c, err := loadAndConfigurePlugin(fileName, l.ldr, l.rf, res) if err != nil { return nil, err } diff --git a/pkg/plugins/transformers.go b/pkg/plugins/transformers.go index b6cf28864..0bf13d392 100644 --- a/pkg/plugins/transformers.go +++ b/pkg/plugins/transformers.go @@ -32,15 +32,19 @@ import ( ) type Configurable interface { - Config(k ifc.Kunstructured) error + Config(ldr ifc.Loader, rf *resmap.Factory, k ifc.Kunstructured) error } type transformerLoader struct { - pc *types.PluginConfig + pc *types.PluginConfig + ldr ifc.Loader + rf *resmap.Factory } -func NewTransformerLoader(pc *types.PluginConfig) transformerLoader { - return transformerLoader{pc: pc} +func NewTransformerLoader( + pc *types.PluginConfig, + ldr ifc.Loader, rf *resmap.Factory) transformerLoader { + return transformerLoader{pc: pc, ldr: ldr, rf: rf} } func (l transformerLoader) Load( @@ -54,7 +58,7 @@ func (l transformerLoader) Load( var result []transformers.Transformer for id, res := range rm { fileName := pluginFileName(l.pc, id) - c, err := loadAndConfigurePlugin(fileName, res) + c, err := loadAndConfigurePlugin(fileName, l.ldr, l.rf, res) if err != nil { return nil, err } @@ -74,7 +78,8 @@ func pluginFileName(pc *types.PluginConfig, id resid.ResId) string { } func loadAndConfigurePlugin( - fileName string, res *resource.Resource) (Configurable, error) { + fileName string, ldr ifc.Loader, + rf *resmap.Factory, res *resource.Resource) (Configurable, error) { goPlugin, err := plugin.Open(fileName) if err != nil { return nil, fmt.Errorf("plugin %s file not opened", fileName) @@ -88,7 +93,7 @@ func loadAndConfigurePlugin( if !ok { return nil, fmt.Errorf("plugin %s not configurable", fileName) } - err = c.Config(res) + err = c.Config(ldr, rf, res) if err != nil { return nil, errors.Wrapf(err, "plugin %s fails configuration", fileName) } diff --git a/pkg/target/generatorplugin_test.go b/pkg/target/generatorplugin_test.go index a0d3b5140..097417efd 100644 --- a/pkg/target/generatorplugin_test.go +++ b/pkg/target/generatorplugin_test.go @@ -14,12 +14,13 @@ limitations under the License. package target_test import ( + "path/filepath" "testing" "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" ) -func writeGenerator(th *KustTestHarness, path string) { +func writeServiceGenerator(th *KustTestHarness, path string) { th.writeF(path, ` apiVersion: someteam.example.com/v1 kind: ServiceGenerator @@ -30,7 +31,7 @@ port: "12345" `) } -func TestGeneratorPlugin(t *testing.T) { +func TestServiceGeneratorPlugin(t *testing.T) { tc := NewTestEnvController(t).Set() defer tc.Reset() @@ -43,7 +44,7 @@ func TestGeneratorPlugin(t *testing.T) { generators: - serviceGenerator.yaml `) - writeGenerator(th, "/app/serviceGenerator.yaml") + writeServiceGenerator(th, "/app/serviceGenerator.yaml") m, err := th.makeKustTarget().MakeCustomizedResMap() if err != nil { t.Fatalf("Err: %v", err) @@ -62,3 +63,67 @@ spec: app: dev `) } + +func writeSecretGeneratorConfig(th *KustTestHarness, root string) { + th.writeF(filepath.Join(root, "secretGenerator.yaml"), ` +apiVersion: kustomize.config.k8s.io/v1 +kind: SecretGenerator +metadata: + name: secretGenerator +name: mySecret +behavior: merge +envFiles: +- a.env +- b.env +valueFiles: +- longsecret.txt +literals: +- FRUIT=apple +- VEGETABLE=carrot +`) + th.writeF(filepath.Join(root, "a.env"), ` +ROUTER_PASSWORD=admin +`) + th.writeF(filepath.Join(root, "b.env"), ` +DB_PASSWORD=iloveyou +`) + th.writeF(filepath.Join(root, "longsecret.txt"), ` +Lorem ipsum dolor sit amet, +consectetur adipiscing elit, +sed do eiusmod tempor incididunt +ut labore et dolore magna aliqua. +`) +} + +// nolint:lll +func TestSecretGenerator(t *testing.T) { + tc := NewTestEnvController(t).Set() + defer tc.Reset() + + tc.BuildGoPlugin( + "kustomize.config.k8s.io", "v1", "SecretGenerator") + + th := NewKustTestHarnessWithPluginConfig( + t, "/app", plugin.ActivePluginConfig()) + th.writeK("/app", ` +generators: +- secretGenerator.yaml +`) + writeSecretGeneratorConfig(th, "/app") + m, err := th.makeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.assertActualEqualsExpected(m, ` +apiVersion: v1 +data: + FRUIT: YXBwbGU= + ROUTER_PASSWORD: YWRtaW4= + VEGETABLE: Y2Fycm90 + longsecret.txt: CkxvcmVtIGlwc3VtIGRvbG9yIHNpdCBhbWV0LApjb25zZWN0ZXR1ciBhZGlwaXNjaW5nIGVsaXQsCnNlZCBkbyBlaXVzbW9kIHRlbXBvciBpbmNpZGlkdW50CnV0IGxhYm9yZSBldCBkb2xvcmUgbWFnbmEgYWxpcXVhLgo= +kind: Secret +metadata: + name: -2kt2h55789 +type: Opaque +`) +} diff --git a/pkg/target/kusttarget.go b/pkg/target/kusttarget.go index ac5589927..cb5e2e3c2 100644 --- a/pkg/target/kusttarget.go +++ b/pkg/target/kusttarget.go @@ -365,7 +365,8 @@ func (kt *KustTarget) loadTransformerPlugins() ([]transformers.Transformer, erro if err != nil { return nil, err } - return plugins.NewTransformerLoader(kt.pluginConfig).Load(configs) + return plugins.NewTransformerLoader( + kt.pluginConfig, kt.ldr, kt.rFactory).Load(configs) } func (kt *KustTarget) loadGeneratorPlugins() ([]transformers.Generator, error) { @@ -374,5 +375,6 @@ func (kt *KustTarget) loadGeneratorPlugins() ([]transformers.Generator, error) { if err != nil { return nil, err } - return plugins.NewGeneratorLoader(kt.pluginConfig).Load(configs) + return plugins.NewGeneratorLoader( + kt.pluginConfig, kt.ldr, kt.rFactory).Load(configs) } diff --git a/plugins/kustomize.config.k8s.io/v1/SecretGenerator.go b/plugins/kustomize.config.k8s.io/v1/SecretGenerator.go new file mode 100644 index 000000000..500e24b9d --- /dev/null +++ b/plugins/kustomize.config.k8s.io/v1/SecretGenerator.go @@ -0,0 +1,62 @@ +// +build plugin + +package main + +import ( + "fmt" + + "sigs.k8s.io/kustomize/pkg/ifc" + "sigs.k8s.io/kustomize/pkg/resmap" + "sigs.k8s.io/kustomize/pkg/types" +) + +type plugin struct { + ldr ifc.Loader + rf *resmap.Factory + options types.GeneratorOptions + args types.SecretArgs +} + +var KustomizePlugin plugin + +func (p *plugin) Config( + ldr ifc.Loader, rf *resmap.Factory, k ifc.Kunstructured) error { + p.ldr = ldr + p.rf = rf + + var err error + // TODO: Should validate this. + p.args.Behavior, err = k.GetFieldValue("behavior") + if err != nil { + return err + } + + envFiles, err := k.GetStringSlice("envFiles") + if err != nil { + return err + } + if len(envFiles) > 2 { + // TODO: refactor to allow this + return fmt.Errorf("cannot yet accept more than one envFile") + } + if len(envFiles) > 0 { + p.args.EnvSource = envFiles[0] + } + + p.args.FileSources, err = k.GetStringSlice("valueFiles") + if err != nil { + return err + } + p.args.LiteralSources, err = k.GetStringSlice("literals") + if err != nil { + return err + } + + return nil +} + +func (p *plugin) Generate() (resmap.ResMap, error) { + argsList := make([]types.SecretArgs, 1) + argsList[0] = p.args + return p.rf.NewResMapFromSecretArgs(p.ldr, &p.options, argsList) +} diff --git a/plugins/someteam.example.com/v1/DatePrefixer.go b/plugins/someteam.example.com/v1/DatePrefixer.go index df389b283..7c316034d 100644 --- a/plugins/someteam.example.com/v1/DatePrefixer.go +++ b/plugins/someteam.example.com/v1/DatePrefixer.go @@ -15,7 +15,8 @@ type plugin struct{} var KustomizePlugin plugin -func (p *plugin) Config(k ifc.Kunstructured) error { +func (p *plugin) Config( + ldr ifc.Loader, rf *resmap.Factory, k ifc.Kunstructured) error { return nil } diff --git a/plugins/someteam.example.com/v1/ServiceGenerator.go b/plugins/someteam.example.com/v1/ServiceGenerator.go index eb80a84de..baf077087 100644 --- a/plugins/someteam.example.com/v1/ServiceGenerator.go +++ b/plugins/someteam.example.com/v1/ServiceGenerator.go @@ -33,7 +33,8 @@ spec: app: dev ` -func (p *plugin) Config(k ifc.Kunstructured) error { +func (p *plugin) Config( + ldr ifc.Loader, rf *resmap.Factory, k ifc.Kunstructured) error { var err error p.ServiceName, err = k.GetFieldValue("service") if err != nil { diff --git a/plugins/someteam.example.com/v1/StringPrefixer.go b/plugins/someteam.example.com/v1/StringPrefixer.go index 78961e375..230bcd697 100644 --- a/plugins/someteam.example.com/v1/StringPrefixer.go +++ b/plugins/someteam.example.com/v1/StringPrefixer.go @@ -24,7 +24,8 @@ type plugin struct { var KustomizePlugin plugin -func (p *plugin) Config(k ifc.Kunstructured) error { +func (p *plugin) Config( + ldr ifc.Loader, rf *resmap.Factory, k ifc.Kunstructured) error { var err error p.prefix, err = k.GetFieldValue("prefix") if err != nil {