diff --git a/k8sdeps/configmapandsecret/basefactory.go b/k8sdeps/configmapandsecret/basefactory.go index dd1a4d64e..b1bad0bcf 100644 --- a/k8sdeps/configmapandsecret/basefactory.go +++ b/k8sdeps/configmapandsecret/basefactory.go @@ -18,7 +18,6 @@ package configmapandsecret import ( "fmt" - "path" "strings" "github.com/pkg/errors" @@ -82,7 +81,7 @@ func errIfInvalidKey(keyName string) error { func keyValuesFromLiteralSources(sources []string) ([]kv.Pair, error) { var kvs []kv.Pair for _, s := range sources { - k, v, err := parseLiteralSource(s) + k, v, err := kv.ParseLiteralSource(s) if err != nil { return nil, err } @@ -110,7 +109,7 @@ func (bf baseFactory) keyValuesFromPlugins(sources []types.KVSource) ([]kv.Pair, func (bf baseFactory) keyValuesFromFileSources(sources []string) ([]kv.Pair, error) { var kvs []kv.Pair for _, s := range sources { - k, fPath, err := parseFileSource(s) + k, fPath, err := kv.ParseFileSource(s) if err != nil { return nil, err } @@ -133,44 +132,3 @@ func (bf baseFactory) keyValuesFromEnvFile(path string) ([]kv.Pair, error) { } return kv.KeyValuesFromLines(content) } - -// parseFileSource parses the source given. -// -// Acceptable formats include: -// 1. source-path: the basename will become the key name -// 2. source-name=source-path: the source-name will become the key name and -// source-path is the path to the key file. -// -// Key names cannot include '='. -func parseFileSource(source string) (keyName, filePath string, err error) { - numSeparators := strings.Count(source, "=") - switch { - case numSeparators == 0: - return path.Base(source), source, nil - case numSeparators == 1 && strings.HasPrefix(source, "="): - return "", "", fmt.Errorf("key name for file path %v missing", strings.TrimPrefix(source, "=")) - case numSeparators == 1 && strings.HasSuffix(source, "="): - return "", "", fmt.Errorf("file path for key name %v missing", strings.TrimSuffix(source, "=")) - case numSeparators > 1: - return "", "", errors.New("key names or file paths cannot contain '='") - default: - components := strings.Split(source, "=") - return components[0], components[1], nil - } -} - -// parseLiteralSource parses the source key=val pair into its component pieces. -// This functionality is distinguished from strings.SplitN(source, "=", 2) since -// it returns an error in the case of empty keys, values, or a missing equals sign. -func parseLiteralSource(source string) (keyName, value string, err error) { - // leading equal is invalid - if strings.Index(source, "=") == 0 { - return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source) - } - // split after the first equal (so values can have the = character) - items := strings.SplitN(source, "=", 2) - if len(items) != 2 { - return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source) - } - return items[0], strings.Trim(items[1], "\"'"), nil -} diff --git a/k8sdeps/configmapandsecret/basefactory_test.go b/k8sdeps/configmapandsecret/basefactory_test.go index d96092fc1..3f0a545d5 100644 --- a/k8sdeps/configmapandsecret/basefactory_test.go +++ b/k8sdeps/configmapandsecret/basefactory_test.go @@ -68,26 +68,22 @@ func TestKeyValuesFromPlugins(t *testing.T) { expected []kv.Pair }{ { - description: "Create kv.Pairs from plugin", + description: "Create kv.Pairs from builtin literals plugin", sources: []types.KVSource{ { - PluginType: "testonly", - Name: "testonly", - Args: []string{"FOO", "BAR", "BAZ"}, + PluginType: "builtin", + Name: "literals", + Args: []string{"FOO=bar", "BAR=baz"}, }, }, expected: []kv.Pair{ { - Key: "k_FOO", - Value: "v_FOO", + Key: "FOO", + Value: "bar", }, { - Key: "k_BAR", - Value: "v_BAR", - }, - { - Key: "k_BAZ", - Value: "v_BAZ", + Key: "BAR", + Value: "baz", }, }, }, diff --git a/k8sdeps/kv/plugin/testonly.go b/k8sdeps/kv/plugin/builtin/literals.go similarity index 57% rename from k8sdeps/kv/plugin/testonly.go rename to k8sdeps/kv/plugin/builtin/literals.go index ecbc36cc8..8896e7104 100644 --- a/k8sdeps/kv/plugin/testonly.go +++ b/k8sdeps/kv/plugin/builtin/literals.go @@ -14,30 +14,26 @@ See the License for the specific language governing permissions and limitations under the License. */ -// testonly is temporary until we have builtin plugins to use in the tests. - -package plugin +package builtin import ( "sigs.k8s.io/kustomize/k8sdeps/kv" ) -var _ Factory = &testonlyFactory{} +// Literals takes a list of literals. +// Each literal source should be a key and literal value, +// e.g. `somekey=somevalue` +type Literals struct{} -func newTestonlyFactory() *testonlyFactory { - return &testonlyFactory{} -} - -type testonlyFactory struct{} - -func (p testonlyFactory) Get(_ string, args []string) ([]kv.Pair, error) { +// Get implements the interface for kv plugins. +func (p Literals) Get(root string, args []string) ([]kv.Pair, error) { var kvs []kv.Pair - for _, arg := range args { - kvs = append(kvs, kv.Pair{Key: "k_" + arg, Value: "v_" + arg}) + for _, s := range args { + k, v, err := kv.ParseLiteralSource(s) + if err != nil { + return nil, err + } + kvs = append(kvs, kv.Pair{Key: k, Value: v}) } return kvs, nil } - -func (p *testonlyFactory) load(_ string) (KVSource, error) { - return p, nil -} diff --git a/k8sdeps/kv/plugin/builtinplugin.go b/k8sdeps/kv/plugin/builtinplugin.go new file mode 100644 index 000000000..3af666dd4 --- /dev/null +++ b/k8sdeps/kv/plugin/builtinplugin.go @@ -0,0 +1,45 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugin + +import ( + "fmt" + + "sigs.k8s.io/kustomize/k8sdeps/kv/plugin/builtin" + "sigs.k8s.io/kustomize/pkg/ifc" +) + +var _ Factory = &builtinFactory{} + +type builtinFactory struct { + plugins map[string]KVSource +} + +func newBuiltinFactory(_ ifc.Loader) *builtinFactory { + return &builtinFactory{ + plugins: map[string]KVSource{ + "literals": builtin.Literals{}, + }, + } +} + +func (p *builtinFactory) load(name string) (KVSource, error) { + if plug, ok := p.plugins[name]; ok { + return plug, nil + } + return nil, fmt.Errorf("plugin %s not found", name) +} diff --git a/k8sdeps/kv/plugin/registry.go b/k8sdeps/kv/plugin/registry.go index 9e7447f29..183ed16e3 100644 --- a/k8sdeps/kv/plugin/registry.go +++ b/k8sdeps/kv/plugin/registry.go @@ -49,8 +49,8 @@ func NewConfiguredRegistry( return Registry{ ldr: ldr, factories: map[string]Factory{ - "go": newGoFactory(pc), - "testonly": newTestonlyFactory(), + "go": newGoFactory(pc), + "builtin": newBuiltinFactory(ldr), }, } } diff --git a/k8sdeps/kv/util.go b/k8sdeps/kv/util.go new file mode 100644 index 000000000..0fe67ed35 --- /dev/null +++ b/k8sdeps/kv/util.go @@ -0,0 +1,65 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kv + +import ( + "errors" + "fmt" + "path" + "strings" +) + +// ParseFileSource parses the source given. +// +// Acceptable formats include: +// 1. source-path: the basename will become the key name +// 2. source-name=source-path: the source-name will become the key name and +// source-path is the path to the key file. +// +// Key names cannot include '='. +func ParseFileSource(source string) (keyName, filePath string, err error) { + numSeparators := strings.Count(source, "=") + switch { + case numSeparators == 0: + return path.Base(source), source, nil + case numSeparators == 1 && strings.HasPrefix(source, "="): + return "", "", fmt.Errorf("key name for file path %v missing", strings.TrimPrefix(source, "=")) + case numSeparators == 1 && strings.HasSuffix(source, "="): + return "", "", fmt.Errorf("file path for key name %v missing", strings.TrimSuffix(source, "=")) + case numSeparators > 1: + return "", "", errors.New("key names or file paths cannot contain '='") + default: + components := strings.Split(source, "=") + return components[0], components[1], nil + } +} + +// ParseLiteralSource parses the source key=val pair into its component pieces. +// This functionality is distinguished from strings.SplitN(source, "=", 2) since +// it returns an error in the case of empty keys, values, or a missing equals sign. +func ParseLiteralSource(source string) (keyName, value string, err error) { + // leading equal is invalid + if strings.Index(source, "=") == 0 { + return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source) + } + // split after the first equal (so values can have the = character) + items := strings.SplitN(source, "=", 2) + if len(items) != 2 { + return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source) + } + return items[0], strings.Trim(items[1], "\"'"), nil +} diff --git a/pkg/target/configmaps_test.go b/pkg/target/configmaps_test.go index 3ba0545d8..c482b6a7d 100644 --- a/pkg/target/configmaps_test.go +++ b/pkg/target/configmaps_test.go @@ -247,11 +247,11 @@ func TestGeneratorPlugins(t *testing.T) { secretGenerator: - name: bob kvSources: - - pluginType: testonly - name: testonly + - pluginType: builtin + name: literals args: - - FRUIT - - VEGETABLE + - FRUIT=apple + - VEGETABLE=carrot `) m, err := th.makeKustTarget().MakeCustomizedResMap() if err != nil { @@ -260,11 +260,11 @@ secretGenerator: th.assertActualEqualsExpected(m, ` apiVersion: v1 data: - k_FRUIT: dl9GUlVJVA== - k_VEGETABLE: dl9WRUdFVEFCTEU= + FRUIT: YXBwbGU= + VEGETABLE: Y2Fycm90 kind: Secret metadata: - name: bob-cb9mhbh9gg + name: bob-bgtct8h699 type: Opaque `) }