diff --git a/examples/zh/README-CN.md b/examples/zh/README-CN.md index d237659d8..1ed77c568 100644 --- a/examples/zh/README-CN.md +++ b/examples/zh/README-CN.md @@ -6,7 +6,6 @@ 这些示例通过了 [pre-commit](../../bin/pre-commit.sh) 测试,并且应该与 HEAD 一起使用。 - ``` go get sigs.k8s.io/kustomize ``` @@ -26,7 +25,7 @@ go get sigs.k8s.io/kustomize * [configGenerations](../configGeneration.md) - 当 ConfigMapGenerator 修改时进行滚动更新。 - * [secret generation](../kvSourceGoPlugin.md) - 生成 Secret。 + * [secret generation](../secretGeneratorPlugin.md) - 生成 Secret。 * [generatorOptions](../generatorOptions.md) -修改所有 ConfigMapGenerator 和 SecretGenerator 的行为。 diff --git a/internal/loadertest/fakeloader.go b/internal/loadertest/fakeloader.go index df5a03cc6..4accf4574 100644 --- a/internal/loadertest/fakeloader.go +++ b/internal/loadertest/fakeloader.go @@ -1,18 +1,5 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 // Package loadertest holds a fake for the Loader interface. package loadertest @@ -22,6 +9,8 @@ import ( "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/loader" + "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" ) // FakeLoader encapsulates the delegate Loader and the fake file system. @@ -46,7 +35,8 @@ func NewFakeLoaderWithRestrictor( // Create fake filesystem and inject it into initial Loader. fSys := fs.MakeFakeFS() fSys.Mkdir(initialDir) - ldr, err := loader.NewLoader(lr, initialDir, fSys) + ldr, err := loader.NewLoader( + lr, validators.MakeFakeValidator(), initialDir, fSys) if err != nil { log.Fatalf("Unable to make loader: %v", err) } @@ -63,7 +53,7 @@ func (f FakeLoader) AddDirectory(fullDirPath string) error { return f.fs.Mkdir(fullDirPath) } -// Root returns root. +// Root delegates. func (f FakeLoader) Root() string { return f.delegate.Root() } @@ -77,12 +67,22 @@ func (f FakeLoader) New(newRoot string) (ifc.Loader, error) { return FakeLoader{fs: f.fs, delegate: l}, nil } -// Load performs load from a given location. +// Load delegates. func (f FakeLoader) Load(location string) ([]byte, error) { return f.delegate.Load(location) } -// Cleanup does nothing +// Cleanup delegates. func (f FakeLoader) Cleanup() error { - return nil + return f.delegate.Cleanup() +} + +// Validator delegates. +func (f FakeLoader) Validator() ifc.Validator { + return f.delegate.Validator() +} + +// LoadKvPairs delegates. +func (f FakeLoader) LoadKvPairs(args types.GeneratorArgs) ([]types.Pair, error) { + return f.delegate.LoadKvPairs(args) } diff --git a/k8sdeps/configmapandsecret/configmapfactory.go b/k8sdeps/configmapandsecret/configmapfactory.go index b9b660001..7bb0145c8 100644 --- a/k8sdeps/configmapandsecret/configmapfactory.go +++ b/k8sdeps/configmapandsecret/configmapfactory.go @@ -1,18 +1,5 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 // Package configmapandsecret generates configmaps and secrets per generator rules. package configmapandsecret @@ -39,13 +26,13 @@ func makeFreshConfigMap( // MakeConfigMap returns a new ConfigMap, or nil and an error. func (f *Factory) MakeConfigMap( args *types.ConfigMapArgs) (*v1.ConfigMap, error) { - all, err := f.loadKvPairs(args.GeneratorArgs) + all, err := f.ldr.LoadKvPairs(args.GeneratorArgs) if err != nil { return nil, err } cm := makeFreshConfigMap(args) for _, p := range all { - err = addKvToConfigMap(cm, p.Key, p.Value) + err = f.addKvToConfigMap(cm, p) if err != nil { return nil, err } @@ -59,26 +46,26 @@ func (f *Factory) MakeConfigMap( // addKvToConfigMap adds the given key and data to the given config map. // Error if key invalid, or already exists. -func addKvToConfigMap(configMap *v1.ConfigMap, keyName, data string) error { - if err := errIfInvalidKey(keyName); err != nil { +func (f *Factory) addKvToConfigMap(configMap *v1.ConfigMap, p types.Pair) error { + if err := f.ldr.Validator().ErrIfInvalidKey(p.Key); err != nil { return err } // If the configmap data contains byte sequences that are all in the UTF-8 // range, we will write it to .Data - if utf8.Valid([]byte(data)) { - if _, entryExists := configMap.Data[keyName]; entryExists { - return fmt.Errorf(keyExistsErrorMsg, keyName, configMap.Data) + if utf8.Valid([]byte(p.Value)) { + if _, entryExists := configMap.Data[p.Key]; entryExists { + return fmt.Errorf(keyExistsErrorMsg, p.Key, configMap.Data) } - configMap.Data[keyName] = data + configMap.Data[p.Key] = p.Value return nil } // otherwise, it's BinaryData if configMap.BinaryData == nil { configMap.BinaryData = map[string][]byte{} } - if _, entryExists := configMap.BinaryData[keyName]; entryExists { - return fmt.Errorf(keyExistsErrorMsg, keyName, configMap.BinaryData) + if _, entryExists := configMap.BinaryData[p.Key]; entryExists { + return fmt.Errorf(keyExistsErrorMsg, p.Key, configMap.BinaryData) } - configMap.BinaryData[keyName] = []byte(data) + configMap.BinaryData[p.Key] = []byte(p.Value) return nil } diff --git a/k8sdeps/configmapandsecret/configmapfactory_test.go b/k8sdeps/configmapandsecret/configmapfactory_test.go index a163d9031..85611caae 100644 --- a/k8sdeps/configmapandsecret/configmapfactory_test.go +++ b/k8sdeps/configmapandsecret/configmapfactory_test.go @@ -12,6 +12,7 @@ import ( "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" ) func makeEnvConfigMap(name string) *corev1.ConfigMap { @@ -128,7 +129,7 @@ func TestConstructConfigMap(t *testing.T) { fSys.WriteFile("/configmap/app.env", []byte("DB_USERNAME=admin\nDB_PASSWORD=somepw\n")) fSys.WriteFile("/configmap/app-init.ini", []byte("FOO=bar\nBAR=baz\n")) fSys.WriteFile("/configmap/app.bin", []byte{0xff, 0xfd}) - ldr := loader.NewFileLoaderAtRoot(fSys) + ldr := loader.NewFileLoaderAtRoot(validators.MakeFakeValidator(), fSys) for _, tc := range testCases { f := NewFactory(ldr, tc.options) cm, err := f.MakeConfigMap(&tc.input) diff --git a/k8sdeps/configmapandsecret/factory.go b/k8sdeps/configmapandsecret/factory.go index c52fcf04c..c491749ff 100644 --- a/k8sdeps/configmapandsecret/factory.go +++ b/k8sdeps/configmapandsecret/factory.go @@ -4,12 +4,6 @@ package configmapandsecret import ( - "fmt" - "strings" - - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/util/validation" - "sigs.k8s.io/kustomize/k8sdeps/kv" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/types" ) @@ -20,87 +14,10 @@ type Factory struct { options *types.GeneratorOptions } -// NewFactory returns a new Factory. +// NewFactory returns a new factory that makes ConfigMaps and Secrets. func NewFactory( - l ifc.Loader, o *types.GeneratorOptions) *Factory { - return &Factory{ldr: l, options: o} -} - -func (f *Factory) loadKvPairs( - args types.GeneratorArgs) (all []kv.Pair, err error) { - pairs, err := f.keyValuesFromEnvFiles(args.EnvSources) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf( - "env source files: %v", - args.EnvSources)) - } - all = append(all, pairs...) - - pairs, err = keyValuesFromLiteralSources(args.LiteralSources) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf( - "literal sources %v", args.LiteralSources)) - } - all = append(all, pairs...) - - pairs, err = f.keyValuesFromFileSources(args.FileSources) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf( - "file sources: %v", args.FileSources)) - } - return append(all, pairs...), nil + ldr ifc.Loader, o *types.GeneratorOptions) *Factory { + return &Factory{ldr: ldr, options: o} } const keyExistsErrorMsg = "cannot add key %s, another key by that name already exists: %v" - -func errIfInvalidKey(keyName string) error { - if errs := validation.IsConfigMapKey(keyName); len(errs) != 0 { - return fmt.Errorf("%q is not a valid key name: %s", - keyName, strings.Join(errs, ";")) - } - return nil -} - -func keyValuesFromLiteralSources(sources []string) ([]kv.Pair, error) { - var kvs []kv.Pair - for _, s := range sources { - 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 (f *Factory) keyValuesFromFileSources(sources []string) ([]kv.Pair, error) { - var kvs []kv.Pair - for _, s := range sources { - k, fPath, err := kv.ParseFileSource(s) - if err != nil { - return nil, err - } - content, err := f.ldr.Load(fPath) - if err != nil { - return nil, err - } - kvs = append(kvs, kv.Pair{Key: k, Value: string(content)}) - } - return kvs, nil -} - -func (f *Factory) keyValuesFromEnvFiles(paths []string) ([]kv.Pair, error) { - var kvs []kv.Pair - for _, path := range paths { - content, err := f.ldr.Load(path) - if err != nil { - return nil, err - } - more, err := kv.KeyValuesFromLines(content) - if err != nil { - return nil, err - } - kvs = append(kvs, more...) - } - return kvs, nil -} diff --git a/k8sdeps/configmapandsecret/factory_test.go b/k8sdeps/configmapandsecret/factory_test.go deleted file mode 100644 index 33891ce1b..000000000 --- a/k8sdeps/configmapandsecret/factory_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package configmapandsecret - -import ( - "reflect" - "testing" - - "sigs.k8s.io/kustomize/k8sdeps/kv" - "sigs.k8s.io/kustomize/pkg/fs" - "sigs.k8s.io/kustomize/pkg/loader" -) - -func TestKeyValuesFromFileSources(t *testing.T) { - tests := []struct { - description string - sources []string - expected []kv.Pair - }{ - { - description: "create kvs from file sources", - sources: []string{"files/app-init.ini"}, - expected: []kv.Pair{ - { - Key: "app-init.ini", - Value: "FOO=bar", - }, - }, - }, - } - - fSys := fs.MakeFakeFS() - fSys.WriteFile("/files/app-init.ini", []byte("FOO=bar")) - bf := NewFactory(loader.NewFileLoaderAtRoot(fSys), nil) - for _, tc := range tests { - kvs, err := bf.keyValuesFromFileSources(tc.sources) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !reflect.DeepEqual(kvs, tc.expected) { - t.Fatalf("in testcase: %q updated:\n%#v\ndoesn't match expected:\n%#v\n", tc.description, kvs, tc.expected) - } - } -} diff --git a/k8sdeps/configmapandsecret/secretfactory.go b/k8sdeps/configmapandsecret/secretfactory.go index 34d36f41d..1fe8231f2 100644 --- a/k8sdeps/configmapandsecret/secretfactory.go +++ b/k8sdeps/configmapandsecret/secretfactory.go @@ -1,18 +1,5 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 package configmapandsecret @@ -41,13 +28,13 @@ func makeFreshSecret( // MakeSecret returns a new secret. func (f *Factory) MakeSecret( args *types.SecretArgs) (*corev1.Secret, error) { - all, err := f.loadKvPairs(args.GeneratorArgs) + all, err := f.ldr.LoadKvPairs(args.GeneratorArgs) if err != nil { return nil, err } s := makeFreshSecret(args) for _, p := range all { - err = addKvToSecret(s, p.Key, p.Value) + err = f.addKvToSecret(s, p.Key, p.Value) if err != nil { return nil, err } @@ -59,8 +46,8 @@ func (f *Factory) MakeSecret( return s, nil } -func addKvToSecret(secret *corev1.Secret, keyName, data string) error { - if err := errIfInvalidKey(keyName); err != nil { +func (f *Factory) addKvToSecret(secret *corev1.Secret, keyName, data string) error { + if err := f.ldr.Validator().ErrIfInvalidKey(keyName); err != nil { return err } if _, entryExists := secret.Data[keyName]; entryExists { diff --git a/k8sdeps/configmapandsecret/secretfactory_test.go b/k8sdeps/configmapandsecret/secretfactory_test.go index b1e29fd4a..0e88d0615 100644 --- a/k8sdeps/configmapandsecret/secretfactory_test.go +++ b/k8sdeps/configmapandsecret/secretfactory_test.go @@ -12,6 +12,7 @@ import ( "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" ) func makeEnvSecret(name string) *corev1.Secret { @@ -125,7 +126,7 @@ func TestConstructSecret(t *testing.T) { fSys := fs.MakeFakeFS() fSys.WriteFile("/secret/app.env", []byte("DB_USERNAME=admin\nDB_PASSWORD=somepw\n")) fSys.WriteFile("/secret/app-init.ini", []byte("FOO=bar\nBAR=baz\n")) - ldr := loader.NewFileLoaderAtRoot(fSys) + ldr := loader.NewFileLoaderAtRoot(validators.MakeFakeValidator(), fSys) for _, tc := range testCases { f := NewFactory(ldr, tc.options) cm, err := f.MakeSecret(&tc.input) diff --git a/k8sdeps/kv/kv.go b/k8sdeps/kv/kv.go deleted file mode 100644 index 236a9f6a0..000000000 --- a/k8sdeps/kv/kv.go +++ /dev/null @@ -1,101 +0,0 @@ -/* -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 ( - "bufio" - "bytes" - "fmt" - "os" - "strings" - "unicode" - "unicode/utf8" - - "k8s.io/apimachinery/pkg/util/validation" -) - -type Pair struct { - Key string - Value string -} - -var utf8bom = []byte{0xEF, 0xBB, 0xBF} - -// KeyValuesFromLines parses given content in to a list of key-value pairs. -func KeyValuesFromLines(content []byte) ([]Pair, error) { - var kvs []Pair - - scanner := bufio.NewScanner(bytes.NewReader(content)) - currentLine := 0 - for scanner.Scan() { - // Process the current line, retrieving a key/value pair if - // possible. - scannedBytes := scanner.Bytes() - kv, err := KeyValuesFromLine(scannedBytes, currentLine) - if err != nil { - return nil, err - } - currentLine++ - - if len(kv.Key) == 0 { - // no key means line was empty or a comment - continue - } - - kvs = append(kvs, kv) - } - return kvs, nil -} - -// KeyValuesFromLine returns a kv with blank key if the line is empty or a comment. -// The value will be retrieved from the environment if necessary. -func KeyValuesFromLine(line []byte, currentLine int) (Pair, error) { - kv := Pair{} - - if !utf8.Valid(line) { - return kv, fmt.Errorf("line %d has invalid utf8 bytes : %v", line, string(line)) - } - - // We trim UTF8 BOM from the first line of the file but no others - if currentLine == 0 { - line = bytes.TrimPrefix(line, utf8bom) - } - - // trim the line from all leading whitespace first - line = bytes.TrimLeftFunc(line, unicode.IsSpace) - - // If the line is empty or a comment, we return a blank key/value pair. - if len(line) == 0 || line[0] == '#' { - return kv, nil - } - - data := strings.SplitN(string(line), "=", 2) - key := data[0] - if errs := validation.IsEnvVarName(key); len(errs) != 0 { - return kv, fmt.Errorf("%q is not a valid key name: %s", key, strings.Join(errs, ";")) - } - - if len(data) == 2 { - kv.Value = data[1] - } else { - // No value (no `=` in the line) is a signal to obtain the value - // from the environment. - kv.Value = os.Getenv(key) - } - kv.Key = key - return kv, nil -} diff --git a/k8sdeps/kv/kv_test.go b/k8sdeps/kv/kv_test.go deleted file mode 100644 index f854a917f..000000000 --- a/k8sdeps/kv/kv_test.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -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 ( - "reflect" - "testing" -) - -func TestKeyValuesFromLines(t *testing.T) { - tests := []struct { - desc string - content string - expectedPairs []Pair - expectedErr bool - }{ - { - desc: "valid kv content parse", - content: ` - k1=v1 - k2=v2 - `, - expectedPairs: []Pair{ - {Key: "k1", Value: "v1"}, - {Key: "k2", Value: "v2"}, - }, - expectedErr: false, - }, - { - desc: "content with comments", - content: ` - k1=v1 - #k2=v2 - `, - expectedPairs: []Pair{ - {Key: "k1", Value: "v1"}, - }, - expectedErr: false, - }, - // TODO: add negative testcases - } - - for _, test := range tests { - pairs, err := KeyValuesFromLines([]byte(test.content)) - if test.expectedErr && err == nil { - t.Fatalf("%s should not return error", test.desc) - } - - if !reflect.DeepEqual(pairs, test.expectedPairs) { - t.Errorf("%s should succeed, got:%v exptected:%v", test.desc, pairs, test.expectedPairs) - } - - } -} diff --git a/k8sdeps/kv/util.go b/k8sdeps/kv/util.go deleted file mode 100644 index 0fe67ed35..000000000 --- a/k8sdeps/kv/util.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -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/k8sdeps/transformer/factory.go b/k8sdeps/transformer/factory.go index cb8a11d0c..61dff0ab5 100644 --- a/k8sdeps/transformer/factory.go +++ b/k8sdeps/transformer/factory.go @@ -1,18 +1,5 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 // Package transformer provides transformer factory package transformer @@ -21,6 +8,7 @@ import ( "sigs.k8s.io/kustomize/k8sdeps/transformer/hash" "sigs.k8s.io/kustomize/k8sdeps/transformer/inventory" "sigs.k8s.io/kustomize/k8sdeps/transformer/patch" + "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/transformers" "sigs.k8s.io/kustomize/pkg/types" @@ -48,7 +36,8 @@ func (p *FactoryImpl) MakeHashTransformer() transformers.Transformer { func (p *FactoryImpl) MakeInventoryTransformer( arg *types.Inventory, + ldr ifc.Loader, namespace string, gp types.GarbagePolicy) transformers.Transformer { - return inventory.NewInventoryTransformer(arg, namespace, gp) + return inventory.NewInventoryTransformer(arg, ldr, namespace, gp) } diff --git a/k8sdeps/transformer/inventory/inventory.go b/k8sdeps/transformer/inventory/inventory.go index 102e370d2..61fe389a6 100644 --- a/k8sdeps/transformer/inventory/inventory.go +++ b/k8sdeps/transformer/inventory/inventory.go @@ -8,6 +8,7 @@ import ( "sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/transformer/hash" "sigs.k8s.io/kustomize/pkg/gvk" + "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/inventory" "sigs.k8s.io/kustomize/pkg/resid" "sigs.k8s.io/kustomize/pkg/resmap" @@ -19,6 +20,7 @@ import ( // inventoryTransformer compute the inventory object used in prune type inventoryTransformer struct { garbagePolicy types.GarbagePolicy + ldr ifc.Loader cmName string cmNamespace string } @@ -28,6 +30,7 @@ var _ transformers.Transformer = &inventoryTransformer{} // NewInventoryTransformer makes a inventoryTransformer. func NewInventoryTransformer( p *types.Inventory, + ldr ifc.Loader, namespace string, gp types.GarbagePolicy) transformers.Transformer { if p == nil || p.Type != "ConfigMap" || p.ConfigMap.Namespace != namespace { @@ -35,6 +38,7 @@ func NewInventoryTransformer( } return &inventoryTransformer{ garbagePolicy: gp, + ldr: ldr, cmName: p.ConfigMap.Name, cmNamespace: p.ConfigMap.Namespace, } @@ -82,7 +86,7 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error { } kf := kunstruct.NewKunstructuredFactoryImpl() - k, err := kf.MakeConfigMap(nil, opts, args) + k, err := kf.MakeConfigMap(o.ldr, opts, args) if err != nil { return err } diff --git a/k8sdeps/transformer/inventory/inventory_test.go b/k8sdeps/transformer/inventory/inventory_test.go index 0337a7d11..b2fa210c4 100644 --- a/k8sdeps/transformer/inventory/inventory_test.go +++ b/k8sdeps/transformer/inventory/inventory_test.go @@ -1,18 +1,5 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 package inventory @@ -21,11 +8,14 @@ import ( "testing" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" + "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/gvk" + "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/resid" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" ) var secret = gvk.Gvk{Version: "v1", Kind: "Secret"} @@ -106,6 +96,7 @@ func makeResMap() resmap.ResMap { func TestInventoryTransformer(t *testing.T) { rf := resource.NewFactory( kunstruct.NewKunstructuredFactoryImpl()) + ldr := loader.NewFileLoaderAtCwd(validators.MakeFakeValidator(), fs.MakeFakeFS()) // hash is derived based on all keys in the Inventory // It is added to annotations as @@ -148,7 +139,7 @@ func TestInventoryTransformer(t *testing.T) { objs := makeResMap() // include the original resmap; only return the ConfigMap for pruning - tran := NewInventoryTransformer(p, "default", types.GarbageCollect) + tran := NewInventoryTransformer(p, ldr, "default", types.GarbageCollect) tran.Transform(objs) if !reflect.DeepEqual(objs, expected) { @@ -160,7 +151,7 @@ func TestInventoryTransformer(t *testing.T) { expected = objs.DeepCopy(rf) expected[resid.NewResIdWithPrefixNamespace(cmap, "pruneCM", "", "default")] = pruneMap // append the ConfigMap for pruning to the original resmap - tran = NewInventoryTransformer(p, "default", types.GarbageIgnore) + tran = NewInventoryTransformer(p, ldr, "default", types.GarbageIgnore) tran.Transform(objs) if !reflect.DeepEqual(objs, expected) { diff --git a/k8sdeps/validator/validators.go b/k8sdeps/validator/validators.go index 563e8d6b9..ffbed5b46 100644 --- a/k8sdeps/validator/validators.go +++ b/k8sdeps/validator/validators.go @@ -1,24 +1,15 @@ -/* -Copyright 2018 The Kubernetes Authors. +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 -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 validator provides functions to validate labels, annotations, namespace using apimachinery +// Package validator provides functions to validate labels, annotations, +// namespaces and configmap/secret keys using apimachinery functions. package validator import ( "errors" + "fmt" + "strings" + apivalidation "k8s.io/apimachinery/pkg/api/validation" v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/util/validation" @@ -33,6 +24,24 @@ func NewKustValidator() *KustValidator { return &KustValidator{} } +func (v *KustValidator) ErrIfInvalidKey(k string) error { + if errs := validation.IsConfigMapKey(k); len(errs) != 0 { + return fmt.Errorf( + "%q is not a valid key name: %s", + k, strings.Join(errs, ";")) + } + return nil +} + +func (v *KustValidator) IsEnvVarName(k string) error { + if errs := validation.IsEnvVarName(k); len(errs) != 0 { + return fmt.Errorf( + "%q is not a valid key name: %s", + k, strings.Join(errs, ";")) + } + return nil +} + // MakeAnnotationValidator returns a MapValidatorFunc using apimachinery. func (v *KustValidator) MakeAnnotationValidator() func(map[string]string) error { return func(x map[string]string) error { diff --git a/pkg/commands/build/build.go b/pkg/commands/build/build.go index 95d2f7cb8..5a954780d 100644 --- a/pkg/commands/build/build.go +++ b/pkg/commands/build/build.go @@ -9,6 +9,8 @@ import ( "path/filepath" "strings" + "sigs.k8s.io/kustomize/pkg/ifc" + "github.com/pkg/errors" "github.com/spf13/cobra" "sigs.k8s.io/kustomize/pkg/fs" @@ -54,8 +56,8 @@ url examples: // NewCmdBuild creates a new build command. func NewCmdBuild( - out io.Writer, fs fs.FileSystem, - rf *resmap.Factory, + out io.Writer, fSys fs.FileSystem, + v ifc.Validator, rf *resmap.Factory, ptf transformer.Factory) *cobra.Command { var o Options @@ -72,7 +74,7 @@ func NewCmdBuild( if err != nil { return err } - return o.RunBuild(out, fs, rf, ptf, pl) + return o.RunBuild(out, v, fSys, rf, ptf, pl) }, } @@ -84,7 +86,7 @@ func NewCmdBuild( plugins.AddEnablePluginsFlag( cmd.Flags(), &pluginConfig.Enabled) - cmd.AddCommand(NewCmdBuildPrune(out, fs, rf, ptf, pl)) + cmd.AddCommand(NewCmdBuildPrune(out, v, fSys, rf, ptf, pl)) return cmd } @@ -105,11 +107,11 @@ func (o *Options) Validate(args []string) (err error) { // RunBuild runs build command. func (o *Options) RunBuild( - out io.Writer, fSys fs.FileSystem, + out io.Writer, v ifc.Validator, fSys fs.FileSystem, rf *resmap.Factory, ptf transformer.Factory, pl *plugins.Loader) error { ldr, err := loader.NewLoader( - o.loadRestrictor, o.kustomizationPath, fSys) + o.loadRestrictor, v, o.kustomizationPath, fSys) if err != nil { return err } @@ -126,11 +128,11 @@ func (o *Options) RunBuild( } func (o *Options) RunBuildPrune( - out io.Writer, fSys fs.FileSystem, + out io.Writer, v ifc.Validator, fSys fs.FileSystem, rf *resmap.Factory, ptf transformer.Factory, pl *plugins.Loader) error { ldr, err := loader.NewLoader( - o.loadRestrictor, o.kustomizationPath, fSys) + o.loadRestrictor, v, o.kustomizationPath, fSys) if err != nil { return err } @@ -163,9 +165,8 @@ func (o *Options) emitResources( } func NewCmdBuildPrune( - out io.Writer, fs fs.FileSystem, - rf *resmap.Factory, - ptf transformer.Factory, + out io.Writer, v ifc.Validator, fSys fs.FileSystem, + rf *resmap.Factory, ptf transformer.Factory, pl *plugins.Loader) *cobra.Command { var o Options @@ -179,7 +180,7 @@ func NewCmdBuildPrune( if err != nil { return err } - return o.RunBuildPrune(out, fs, rf, ptf, pl) + return o.RunBuildPrune(out, v, fSys, rf, ptf, pl) }, } return cmd diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 782a9c07b..0a20bd6ce 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -37,11 +37,12 @@ See https://sigs.k8s.io/kustomize uf := kunstruct.NewKunstructuredFactoryImpl() rf := resmap.NewFactory(resource.NewFactory(uf)) + v := validator.NewKustValidator() c.AddCommand( build.NewCmdBuild( - stdOut, fSys, + stdOut, fSys, v, rf, transformer.NewFactoryImpl()), - edit.NewCmdEdit(fSys, validator.NewKustValidator(), uf), + edit.NewCmdEdit(fSys, v, uf), misc.NewCmdConfig(fSys), misc.NewCmdVersion(stdOut), ) diff --git a/pkg/commands/edit/add/all.go b/pkg/commands/edit/add/all.go index 25d791663..ce34f72e4 100644 --- a/pkg/commands/edit/add/all.go +++ b/pkg/commands/edit/add/all.go @@ -1,18 +1,5 @@ -/* -Copyright 2017 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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 package add @@ -23,7 +10,10 @@ import ( ) // NewCmdAdd returns an instance of 'add' subcommand. -func NewCmdAdd(fsys fs.FileSystem, v ifc.Validator, kf ifc.KunstructuredFactory) *cobra.Command { +func NewCmdAdd( + fSys fs.FileSystem, + ldr ifc.Loader, + kf ifc.KunstructuredFactory) *cobra.Command { c := &cobra.Command{ Use: "add", Short: "Adds an item to the kustomization file.", @@ -54,13 +44,13 @@ func NewCmdAdd(fsys fs.FileSystem, v ifc.Validator, kf ifc.KunstructuredFactory) Args: cobra.MinimumNArgs(1), } c.AddCommand( - newCmdAddResource(fsys), - newCmdAddPatch(fsys), - newCmdAddSecret(fsys, kf), - newCmdAddConfigMap(fsys, kf), - newCmdAddBase(fsys), - newCmdAddLabel(fsys, v.MakeLabelValidator()), - newCmdAddAnnotation(fsys, v.MakeAnnotationValidator()), + newCmdAddResource(fSys), + newCmdAddPatch(fSys), + newCmdAddSecret(fSys, ldr, kf), + newCmdAddConfigMap(fSys, ldr, kf), + newCmdAddBase(fSys), + newCmdAddLabel(fSys, ldr.Validator().MakeLabelValidator()), + newCmdAddAnnotation(fSys, ldr.Validator().MakeAnnotationValidator()), ) return c } diff --git a/pkg/commands/edit/add/configmap.go b/pkg/commands/edit/add/configmap.go index 5e2e3924a..f46b5d591 100644 --- a/pkg/commands/edit/add/configmap.go +++ b/pkg/commands/edit/add/configmap.go @@ -8,12 +8,14 @@ import ( "sigs.k8s.io/kustomize/pkg/commands/kustfile" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/ifc" - "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/types" ) // newCmdAddConfigMap returns a new command. -func newCmdAddConfigMap(fSys fs.FileSystem, kf ifc.KunstructuredFactory) *cobra.Command { +func newCmdAddConfigMap( + fSys fs.FileSystem, + ldr ifc.Loader, + kf ifc.KunstructuredFactory) *cobra.Command { var flags flagsAndArgs cmd := &cobra.Command{ Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1]", @@ -52,8 +54,7 @@ func newCmdAddConfigMap(fSys fs.FileSystem, kf ifc.KunstructuredFactory) *cobra. } // Add the flagsAndArgs map to the kustomization file. - err = addConfigMap( - loader.NewFileLoaderAtCwd(fSys), kustomization, flags, kf) + err = addConfigMap(ldr, kustomization, flags, kf) if err != nil { return err } diff --git a/pkg/commands/edit/add/configmap_test.go b/pkg/commands/edit/add/configmap_test.go index 5b1b2d7e7..46479dbb4 100644 --- a/pkg/commands/edit/add/configmap_test.go +++ b/pkg/commands/edit/add/configmap_test.go @@ -7,11 +7,15 @@ import ( "testing" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" ) func TestNewAddConfigMapIsNotNil(t *testing.T) { - if newCmdAddConfigMap(fs.MakeFakeFS(), nil) == nil { + fSys := fs.MakeFakeFS() + ldr := loader.NewFileLoaderAtCwd(validators.MakeFakeValidator(), fSys) + if newCmdAddConfigMap(fSys, ldr, nil) == nil { t.Fatal("newCmdAddConfigMap shouldn't be nil") } } diff --git a/pkg/commands/edit/add/secret.go b/pkg/commands/edit/add/secret.go index 8749f17d3..c5272c1ba 100644 --- a/pkg/commands/edit/add/secret.go +++ b/pkg/commands/edit/add/secret.go @@ -8,12 +8,14 @@ import ( "sigs.k8s.io/kustomize/pkg/commands/kustfile" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/ifc" - "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/types" ) // newCmdAddSecret returns a new command. -func newCmdAddSecret(fSys fs.FileSystem, kf ifc.KunstructuredFactory) *cobra.Command { +func newCmdAddSecret( + fSys fs.FileSystem, + ldr ifc.Loader, + kf ifc.KunstructuredFactory) *cobra.Command { var flags flagsAndArgs cmd := &cobra.Command{ Use: "secret NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--type=Opaque|kubernetes.io/tls]", @@ -52,8 +54,7 @@ func newCmdAddSecret(fSys fs.FileSystem, kf ifc.KunstructuredFactory) *cobra.Com } // Add the flagsAndArgs map to the kustomization file. - err = addSecret( - loader.NewFileLoaderAtCwd(fSys), kustomization, flags, kf) + err = addSecret(ldr, kustomization, flags, kf) if err != nil { return err } diff --git a/pkg/commands/edit/add/secret_test.go b/pkg/commands/edit/add/secret_test.go index 6df3f90dd..93577a106 100644 --- a/pkg/commands/edit/add/secret_test.go +++ b/pkg/commands/edit/add/secret_test.go @@ -7,11 +7,15 @@ import ( "testing" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" ) func TestNewCmdAddSecretIsNotNil(t *testing.T) { - if newCmdAddSecret(fs.MakeFakeFS(), nil) == nil { + fSys := fs.MakeFakeFS() + ldr := loader.NewFileLoaderAtCwd(validators.MakeFakeValidator(), fSys) + if newCmdAddSecret(fSys, ldr, nil) == nil { t.Fatal("newCmdAddSecret shouldn't be nil") } } diff --git a/pkg/commands/edit/all.go b/pkg/commands/edit/all.go index 1b9e76b7e..162ae08d1 100644 --- a/pkg/commands/edit/all.go +++ b/pkg/commands/edit/all.go @@ -1,18 +1,5 @@ -/* -Copyright 2017 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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 package edit @@ -24,10 +11,12 @@ import ( "sigs.k8s.io/kustomize/pkg/commands/edit/set" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/ifc" + "sigs.k8s.io/kustomize/pkg/loader" ) // NewCmdEdit returns an instance of 'edit' subcommand. -func NewCmdEdit(fsys fs.FileSystem, v ifc.Validator, kf ifc.KunstructuredFactory) *cobra.Command { +func NewCmdEdit( + fSys fs.FileSystem, v ifc.Validator, kf ifc.KunstructuredFactory) *cobra.Command { c := &cobra.Command{ Use: "edit", Short: "Edits a kustomization file", @@ -44,11 +33,12 @@ func NewCmdEdit(fsys fs.FileSystem, v ifc.Validator, kf ifc.KunstructuredFactory `, Args: cobra.MinimumNArgs(1), } + c.AddCommand( - add.NewCmdAdd(fsys, v, kf), - set.NewCmdSet(fsys, v), - fix.NewCmdFix(fsys), - remove.NewCmdRemove(fsys), + add.NewCmdAdd(fSys, loader.NewFileLoaderAtCwd(v, fSys), kf), + set.NewCmdSet(fSys, v), + fix.NewCmdFix(fSys), + remove.NewCmdRemove(fSys), ) return c } diff --git a/pkg/ifc/ifc.go b/pkg/ifc/ifc.go index d0251f224..637a831d1 100644 --- a/pkg/ifc/ifc.go +++ b/pkg/ifc/ifc.go @@ -1,18 +1,5 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 // Package ifc holds miscellaneous interfaces used by kustomize. package ifc @@ -27,6 +14,8 @@ type Validator interface { MakeAnnotationValidator() func(map[string]string) error MakeLabelValidator() func(map[string]string) error ValidateNamespace(string) []string + ErrIfInvalidKey(string) error + IsEnvVarName(k string) error } // Loader interface exposes methods to read bytes. @@ -39,6 +28,10 @@ type Loader interface { Load(location string) ([]byte, error) // Cleanup cleans the loader Cleanup() error + // Validator validates data for use in various k8s fields. + Validator() Validator + // Loads pairs. + LoadKvPairs(args types.GeneratorArgs) ([]types.Pair, error) } // Kunstructured allows manipulation of k8s objects diff --git a/pkg/ifc/transformer/factory.go b/pkg/ifc/transformer/factory.go index 79905d9a7..238ebbc2d 100644 --- a/pkg/ifc/transformer/factory.go +++ b/pkg/ifc/transformer/factory.go @@ -1,23 +1,11 @@ -/* -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. -*/ +/// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 // Package patch holds miscellaneous interfaces used by kustomize. package transformer import ( + "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/transformers" "sigs.k8s.io/kustomize/pkg/types" @@ -29,6 +17,7 @@ type Factory interface { MakeHashTransformer() transformers.Transformer MakeInventoryTransformer( p *types.Inventory, + ldr ifc.Loader, namespace string, gp types.GarbagePolicy) transformers.Transformer } diff --git a/pkg/loader/fileloader.go b/pkg/loader/fileloader.go index 4fdf7da39..e46b7fe7c 100644 --- a/pkg/loader/fileloader.go +++ b/pkg/loader/fileloader.go @@ -1,18 +1,5 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 package loader @@ -92,6 +79,9 @@ type fileLoader struct { // Restricts behavior of Load function. loadRestrictor LoadRestrictorFunc + // Used to validate various k8s data fields. + validator ifc.Validator + // If this is non-nil, the files were // obtained from the given repository. repoSpec *git.RepoSpec @@ -110,41 +100,44 @@ const CWD = "." // NewFileLoaderAtCwd returns a loader that loads from ".". // A convenience for kustomize edit commands. -func NewFileLoaderAtCwd(fSys fs.FileSystem) *fileLoader { +func NewFileLoaderAtCwd(v ifc.Validator, fSys fs.FileSystem) *fileLoader { return newLoaderOrDie( - RestrictionRootOnly, fSys, CWD) + RestrictionRootOnly, v, fSys, CWD) } // NewFileLoaderAtRoot returns a loader that loads from "/". // A convenience for tests. -func NewFileLoaderAtRoot(fSys fs.FileSystem) *fileLoader { +func NewFileLoaderAtRoot(v ifc.Validator, fSys fs.FileSystem) *fileLoader { return newLoaderOrDie( - RestrictionRootOnly, fSys, string(filepath.Separator)) + RestrictionRootOnly, v, fSys, string(filepath.Separator)) } // Root returns the absolute path that is prepended to any // relative paths used in Load. -func (l *fileLoader) Root() string { - return l.root.String() +func (fl *fileLoader) Root() string { + return fl.root.String() } func newLoaderOrDie( - lr LoadRestrictorFunc, fSys fs.FileSystem, path string) *fileLoader { + lr LoadRestrictorFunc, v ifc.Validator, + fSys fs.FileSystem, path string) *fileLoader { root, err := demandDirectoryRoot(fSys, path) if err != nil { log.Fatalf("unable to make loader at '%s'; %v", path, err) } return newLoaderAtConfirmedDir( - lr, root, fSys, nil, git.ClonerUsingGitExec) + lr, v, root, fSys, nil, git.ClonerUsingGitExec) } // newLoaderAtConfirmedDir returns a new fileLoader with given root. func newLoaderAtConfirmedDir( lr LoadRestrictorFunc, + v ifc.Validator, root fs.ConfirmedDir, fSys fs.FileSystem, referrer *fileLoader, cloner git.Cloner) *fileLoader { return &fileLoader{ loadRestrictor: lr, + validator: v, root: root, referrer: referrer, fSys: fSys, @@ -175,39 +168,41 @@ func demandDirectoryRoot( // New returns a new Loader, rooted relative to current loader, // or rooted in a temp directory holding a git repo clone. -func (l *fileLoader) New(path string) (ifc.Loader, error) { +func (fl *fileLoader) New(path string) (ifc.Loader, error) { if path == "" { return nil, fmt.Errorf("new root cannot be empty") } repoSpec, err := git.NewRepoSpecFromUrl(path) if err == nil { // Treat this as git repo clone request. - if err := l.errIfRepoCycle(repoSpec); err != nil { + if err := fl.errIfRepoCycle(repoSpec); err != nil { return nil, err } - return newLoaderAtGitClone(repoSpec, l.fSys, l.referrer, l.cloner) + return newLoaderAtGitClone( + repoSpec, fl.validator, fl.fSys, fl.referrer, fl.cloner) } if filepath.IsAbs(path) { return nil, fmt.Errorf("new root '%s' cannot be absolute", path) } - root, err := demandDirectoryRoot(l.fSys, l.root.Join(path)) + root, err := demandDirectoryRoot(fl.fSys, fl.root.Join(path)) if err != nil { return nil, err } - if err := l.errIfGitContainmentViolation(root); err != nil { + if err := fl.errIfGitContainmentViolation(root); err != nil { return nil, err } - if err := l.errIfArgEqualOrHigher(root); err != nil { + if err := fl.errIfArgEqualOrHigher(root); err != nil { return nil, err } return newLoaderAtConfirmedDir( - l.loadRestrictor, root, l.fSys, l, l.cloner), nil + fl.loadRestrictor, fl.validator, root, fl.fSys, fl, fl.cloner), nil } // newLoaderAtGitClone returns a new Loader pinned to a temporary // directory holding a cloned git repo. func newLoaderAtGitClone( - repoSpec *git.RepoSpec, fSys fs.FileSystem, + repoSpec *git.RepoSpec, + v ifc.Validator, fSys fs.FileSystem, referrer *fileLoader, cloner git.Cloner) (ifc.Loader, error) { err := cloner(repoSpec) if err != nil { @@ -229,6 +224,7 @@ func newLoaderAtGitClone( return &fileLoader{ // Clones never allowed to escape root. loadRestrictor: RestrictionRootOnly, + validator: v, root: root, referrer: referrer, repoSpec: repoSpec, @@ -238,9 +234,9 @@ func newLoaderAtGitClone( }, nil } -func (l *fileLoader) errIfGitContainmentViolation( +func (fl *fileLoader) errIfGitContainmentViolation( base fs.ConfirmedDir) error { - containingRepo := l.containingRepo() + containingRepo := fl.containingRepo() if containingRepo == nil { return nil } @@ -256,64 +252,64 @@ func (l *fileLoader) errIfGitContainmentViolation( // Looks back through referrers for a git repo, returning nil // if none found. -func (l *fileLoader) containingRepo() *git.RepoSpec { - if l.repoSpec != nil { - return l.repoSpec +func (fl *fileLoader) containingRepo() *git.RepoSpec { + if fl.repoSpec != nil { + return fl.repoSpec } - if l.referrer == nil { + if fl.referrer == nil { return nil } - return l.referrer.containingRepo() + return fl.referrer.containingRepo() } // errIfArgEqualOrHigher tests whether the argument, // is equal to or above the root of any ancestor. -func (l *fileLoader) errIfArgEqualOrHigher( +func (fl *fileLoader) errIfArgEqualOrHigher( candidateRoot fs.ConfirmedDir) error { - if l.root.HasPrefix(candidateRoot) { + if fl.root.HasPrefix(candidateRoot) { return fmt.Errorf( "cycle detected: candidate root '%s' contains visited root '%s'", - candidateRoot, l.root) + candidateRoot, fl.root) } - if l.referrer == nil { + if fl.referrer == nil { return nil } - return l.referrer.errIfArgEqualOrHigher(candidateRoot) + return fl.referrer.errIfArgEqualOrHigher(candidateRoot) } // TODO(monopole): Distinguish branches? // I.e. Allow a distinction between git URI with // path foo and tag bar and a git URI with the same // path but a different tag? -func (l *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error { +func (fl *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error { // TODO(monopole): Use parsed data instead of Raw(). - if l.repoSpec != nil && - strings.HasPrefix(l.repoSpec.Raw(), newRepoSpec.Raw()) { + if fl.repoSpec != nil && + strings.HasPrefix(fl.repoSpec.Raw(), newRepoSpec.Raw()) { return fmt.Errorf( "cycle detected: URI '%s' referenced by previous URI '%s'", - newRepoSpec.Raw(), l.repoSpec.Raw()) + newRepoSpec.Raw(), fl.repoSpec.Raw()) } - if l.referrer == nil { + if fl.referrer == nil { return nil } - return l.referrer.errIfRepoCycle(newRepoSpec) + return fl.referrer.errIfRepoCycle(newRepoSpec) } // Load returns the content of file at the given path, // else an error. Relative paths are taken relative // to the root. -func (l *fileLoader) Load(path string) ([]byte, error) { +func (fl *fileLoader) Load(path string) ([]byte, error) { if !filepath.IsAbs(path) { - path = l.root.Join(path) + path = fl.root.Join(path) } - path, err := l.loadRestrictor(l.fSys, l.root, path) + path, err := fl.loadRestrictor(fl.fSys, fl.root, path) if err != nil { return nil, err } - return l.fSys.ReadFile(path) + return fl.fSys.ReadFile(path) } // Cleanup runs the cleaner. -func (l *fileLoader) Cleanup() error { - return l.cleaner() +func (fl *fileLoader) Cleanup() error { + return fl.cleaner() } diff --git a/pkg/loader/fileloader_test.go b/pkg/loader/fileloader_test.go index b0f8c81cb..ce126496e 100644 --- a/pkg/loader/fileloader_test.go +++ b/pkg/loader/fileloader_test.go @@ -29,6 +29,7 @@ import ( "sigs.k8s.io/kustomize/pkg/git" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/pgmconfig" + "sigs.k8s.io/kustomize/pkg/validators" ) type testData struct { @@ -63,8 +64,12 @@ func MakeFakeFs(td []testData) fs.FileSystem { return fSys } +func makeLoader() *fileLoader { + return NewFileLoaderAtRoot(validators.MakeFakeValidator(), MakeFakeFs(testCases)) + +} func TestLoaderLoad(t *testing.T) { - l1 := NewFileLoaderAtRoot(MakeFakeFs(testCases)) + l1 := makeLoader() if "/" != l1.Root() { t.Fatalf("incorrect root: '%s'\n", l1.Root()) } @@ -103,7 +108,7 @@ func TestLoaderLoad(t *testing.T) { } func TestLoaderNewSubDir(t *testing.T) { - l1, err := NewFileLoaderAtRoot(MakeFakeFs(testCases)).New("foo/project") + l1, err := makeLoader().New("foo/project") if err != nil { t.Fatalf("unexpected err: %v\n", err) } @@ -125,7 +130,7 @@ func TestLoaderNewSubDir(t *testing.T) { } func TestLoaderBadRelative(t *testing.T) { - l1, err := NewFileLoaderAtRoot(MakeFakeFs(testCases)).New("foo/project/subdir1") + l1, err := makeLoader().New("foo/project/subdir1") if err != nil { t.Fatalf("unexpected err: %v\n", err) } @@ -195,7 +200,7 @@ func TestLoaderBadRelative(t *testing.T) { } func TestLoaderMisc(t *testing.T) { - l := NewFileLoaderAtRoot(MakeFakeFs(testCases)) + l := makeLoader() _, err := l.New("") if err == nil { t.Fatalf("Expected error for empty root location not returned") @@ -297,7 +302,8 @@ func TestRestrictionRootOnlyInRealLoader(t *testing.T) { var l ifc.Loader - l = newLoaderOrDie(RestrictionRootOnly, fSys, dir) + l = newLoaderOrDie( + RestrictionRootOnly, validators.MakeFakeValidator(), fSys, dir) l = doSanityChecksAndDropIntoBase(t, l) @@ -330,7 +336,8 @@ func TestRestrictionNoneInRealLoader(t *testing.T) { var l ifc.Loader - l = newLoaderOrDie(RestrictionNone, fSys, dir) + l = newLoaderOrDie( + RestrictionNone, validators.MakeFakeValidator(), fSys, dir) l = doSanityChecksAndDropIntoBase(t, l) @@ -392,7 +399,7 @@ whatever t.Fatalf("unexpected err: %v\n", err) } l, err := newLoaderAtGitClone( - repoSpec, fSys, nil, + repoSpec, validators.MakeFakeValidator(), fSys, nil, git.DoNothingCloner(fs.ConfirmedDir(coRoot))) if err != nil { t.Fatalf("unexpected err: %v\n", err) @@ -434,7 +441,8 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) { // Establish that a local overlay can navigate // to the local bases. - l1 = newLoaderOrDie(RestrictionRootOnly, fSys, cloneRoot+"/foo/overlay") + l1 = newLoaderOrDie( + RestrictionRootOnly, validators.MakeFakeValidator(), fSys, cloneRoot+"/foo/overlay") if l1.Root() != cloneRoot+"/foo/overlay" { t.Fatalf("unexpected root %s", l1.Root()) } @@ -470,7 +478,7 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) { t.Fatalf("unexpected err: %v\n", err) } l1, err = newLoaderAtGitClone( - repoSpec, fSys, nil, + repoSpec, validators.MakeFakeValidator(), fSys, nil, git.DoNothingCloner(fs.ConfirmedDir(cloneRoot))) if err != nil { t.Fatalf("unexpected err: %v\n", err) @@ -509,7 +517,7 @@ func TestLocalLoaderReferencingGitBase(t *testing.T) { t.Fatalf("unexpected err: %v\n", err) } l1 := newLoaderAtConfirmedDir( - RestrictionRootOnly, root, fSys, nil, + RestrictionRootOnly, validators.MakeFakeValidator(), root, fSys, nil, git.DoNothingCloner(fs.ConfirmedDir(cloneRoot))) if l1.Root() != topDir { t.Fatalf("unexpected root %s", l1.Root()) diff --git a/pkg/loader/kv.go b/pkg/loader/kv.go new file mode 100644 index 000000000..2638f46af --- /dev/null +++ b/pkg/loader/kv.go @@ -0,0 +1,200 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package loader + +import ( + "bufio" + "bytes" + "fmt" + "os" + "path" + "strings" + "unicode" + "unicode/utf8" + + "github.com/pkg/errors" + "sigs.k8s.io/kustomize/pkg/ifc" + "sigs.k8s.io/kustomize/pkg/types" +) + +var utf8bom = []byte{0xEF, 0xBB, 0xBF} + +func (fl *fileLoader) Validator() ifc.Validator { + return fl.validator +} + +func (fl *fileLoader) LoadKvPairs( + args types.GeneratorArgs) (all []types.Pair, err error) { + pairs, err := fl.keyValuesFromEnvFiles(args.EnvSources) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf( + "env source files: %v", + args.EnvSources)) + } + all = append(all, pairs...) + + pairs, err = keyValuesFromLiteralSources(args.LiteralSources) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf( + "literal sources %v", args.LiteralSources)) + } + all = append(all, pairs...) + + pairs, err = fl.keyValuesFromFileSources(args.FileSources) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf( + "file sources: %v", args.FileSources)) + } + return append(all, pairs...), nil +} + +func keyValuesFromLiteralSources(sources []string) ([]types.Pair, error) { + var kvs []types.Pair + for _, s := range sources { + k, v, err := parseLiteralSource(s) + if err != nil { + return nil, err + } + kvs = append(kvs, types.Pair{Key: k, Value: v}) + } + return kvs, nil +} + +func (fl *fileLoader) keyValuesFromFileSources(sources []string) ([]types.Pair, error) { + var kvs []types.Pair + for _, s := range sources { + k, fPath, err := parseFileSource(s) + if err != nil { + return nil, err + } + content, err := fl.Load(fPath) + if err != nil { + return nil, err + } + kvs = append(kvs, types.Pair{Key: k, Value: string(content)}) + } + return kvs, nil +} + +func (fl *fileLoader) keyValuesFromEnvFiles(paths []string) ([]types.Pair, error) { + var kvs []types.Pair + for _, p := range paths { + content, err := fl.Load(p) + if err != nil { + return nil, err + } + more, err := fl.keyValuesFromLines(content) + if err != nil { + return nil, err + } + kvs = append(kvs, more...) + } + return kvs, nil +} + +// keyValuesFromLines parses given content in to a list of key-value pairs. +func (fl *fileLoader) keyValuesFromLines(content []byte) ([]types.Pair, error) { + var kvs []types.Pair + + scanner := bufio.NewScanner(bytes.NewReader(content)) + currentLine := 0 + for scanner.Scan() { + // Process the current line, retrieving a key/value pair if + // possible. + scannedBytes := scanner.Bytes() + kv, err := fl.keyValuesFromLine(scannedBytes, currentLine) + if err != nil { + return nil, err + } + currentLine++ + + if len(kv.Key) == 0 { + // no key means line was empty or a comment + continue + } + + kvs = append(kvs, kv) + } + return kvs, nil +} + +// KeyValuesFromLine returns a kv with blank key if the line is empty or a comment. +// The value will be retrieved from the environment if necessary. +func (fl *fileLoader) keyValuesFromLine(line []byte, currentLine int) (types.Pair, error) { + kv := types.Pair{} + + if !utf8.Valid(line) { + return kv, fmt.Errorf("line %d has invalid utf8 bytes : %v", line, string(line)) + } + + // We trim UTF8 BOM from the first line of the file but no others + if currentLine == 0 { + line = bytes.TrimPrefix(line, utf8bom) + } + + // trim the line from all leading whitespace first + line = bytes.TrimLeftFunc(line, unicode.IsSpace) + + // If the line is empty or a comment, we return a blank key/value pair. + if len(line) == 0 || line[0] == '#' { + return kv, nil + } + + data := strings.SplitN(string(line), "=", 2) + key := data[0] + if err := fl.validator.IsEnvVarName(key); err != nil { + return kv, err + } + + if len(data) == 2 { + kv.Value = data[1] + } else { + // No value (no `=` in the line) is a signal to obtain the value + // from the environment. + kv.Value = os.Getenv(key) + } + kv.Key = key + return kv, nil +} + +// 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/loader/kv_test.go b/pkg/loader/kv_test.go new file mode 100644 index 000000000..388b3f3ce --- /dev/null +++ b/pkg/loader/kv_test.go @@ -0,0 +1,91 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package loader + +import ( + "reflect" + "testing" + + "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" +) + +func TestKeyValuesFromLines(t *testing.T) { + tests := []struct { + desc string + content string + expectedPairs []types.Pair + expectedErr bool + }{ + { + desc: "valid kv content parse", + content: ` + k1=v1 + k2=v2 + `, + expectedPairs: []types.Pair{ + {Key: "k1", Value: "v1"}, + {Key: "k2", Value: "v2"}, + }, + expectedErr: false, + }, + { + desc: "content with comments", + content: ` + k1=v1 + #k2=v2 + `, + expectedPairs: []types.Pair{ + {Key: "k1", Value: "v1"}, + }, + expectedErr: false, + }, + // TODO: add negative testcases + } + + l := NewFileLoaderAtRoot( + validators.MakeFakeValidator(), fs.MakeFakeFS()) + for _, test := range tests { + pairs, err := l.keyValuesFromLines([]byte(test.content)) + if test.expectedErr && err == nil { + t.Fatalf("%s should not return error", test.desc) + } + if !reflect.DeepEqual(pairs, test.expectedPairs) { + t.Errorf("%s should succeed, got:%v exptected:%v", test.desc, pairs, test.expectedPairs) + } + } +} + +func TestKeyValuesFromFileSources(t *testing.T) { + tests := []struct { + description string + sources []string + expected []types.Pair + }{ + { + description: "create kvs from file sources", + sources: []string{"files/app-init.ini"}, + expected: []types.Pair{ + { + Key: "app-init.ini", + Value: "FOO=bar", + }, + }, + }, + } + + fSys := fs.MakeFakeFS() + fSys.WriteFile("/files/app-init.ini", []byte("FOO=bar")) + l := NewFileLoaderAtRoot(validators.MakeFakeValidator(), fSys) + for _, tc := range tests { + kvs, err := l.keyValuesFromFileSources(tc.sources) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(kvs, tc.expected) { + t.Fatalf("in testcase: %q updated:\n%#v\ndoesn't match expected:\n%#v\n", tc.description, kvs, tc.expected) + } + } +} diff --git a/pkg/loader/loader.go b/pkg/loader/loader.go index 5bc23a58b..c2dfb5218 100644 --- a/pkg/loader/loader.go +++ b/pkg/loader/loader.go @@ -31,17 +31,18 @@ import ( // the remote bases will all be root-only restricted. func NewLoader( lr LoadRestrictorFunc, + v ifc.Validator, target string, fSys fs.FileSystem) (ifc.Loader, error) { repoSpec, err := git.NewRepoSpecFromUrl(target) if err == nil { // The target qualifies as a remote git target. return newLoaderAtGitClone( - repoSpec, fSys, nil, git.ClonerUsingGitExec) + repoSpec, v, fSys, nil, git.ClonerUsingGitExec) } root, err := demandDirectoryRoot(fSys, target) if err != nil { return nil, err } return newLoaderAtConfirmedDir( - lr, root, fSys, nil, git.ClonerUsingGitExec), nil + lr, v, root, fSys, nil, git.ClonerUsingGitExec), nil } diff --git a/pkg/plugins/config.go b/pkg/plugins/config.go index aea287dbd..2edd2ed34 100644 --- a/pkg/plugins/config.go +++ b/pkg/plugins/config.go @@ -38,7 +38,7 @@ func DefaultPluginConfig() *types.PluginConfig { } } -func PluginsNotEnabledErr(name string) error { +func NotEnabledErr(name string) error { return fmt.Errorf( flagErrorFmt, name, diff --git a/pkg/plugins/loader.go b/pkg/plugins/loader.go index 97509a2ff..7b58bb61a 100644 --- a/pkg/plugins/loader.go +++ b/pkg/plugins/loader.go @@ -103,7 +103,7 @@ func (l *Loader) absolutePluginPath(id resid.ResId) string { func (l *Loader) loadAndConfigurePlugin( ldr ifc.Loader, res *resource.Resource) (c Configurable, err error) { if !l.pc.Enabled { - return nil, PluginsNotEnabledErr(res.Id().Gvk().Kind) + return nil, NotEnabledErr(res.Id().Gvk().Kind) } if p := NewExecPlugin( l.absolutePluginPath(res.Id())); p.isAvailable() { diff --git a/pkg/resmap/factory_test.go b/pkg/resmap/factory_test.go index 6fbcffff6..5b2360f95 100644 --- a/pkg/resmap/factory_test.go +++ b/pkg/resmap/factory_test.go @@ -29,6 +29,7 @@ import ( "sigs.k8s.io/kustomize/pkg/resid" . "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" ) func TestFromFile(t *testing.T) { @@ -52,7 +53,6 @@ metadata: namespace: test --- ` - l := loadertest.NewFakeLoader("/whatever/project") if ferr := l.AddFile("/whatever/project/deployment.yaml", []byte(resourceStr)); ferr != nil { t.Fatalf("Error adding fake file: %v\n", ferr) @@ -173,6 +173,7 @@ func TestNewFromConfigMaps(t *testing.T) { }, &types.GeneratorArgs{}, nil), }, }, + { description: "construct config map from file", input: []types.ConfigMapArgs{{ @@ -231,6 +232,7 @@ BAR=baz }, &types.GeneratorArgs{}, nil), }, }, + // TODO: add testcase for data coming from multiple sources like // files/literal/env etc. } @@ -268,7 +270,7 @@ func TestNewResMapFromSecretArgs(t *testing.T) { fakeFs := fs.MakeFakeFS() fakeFs.Mkdir(".") actual, err := rmF.NewResMapFromSecretArgs( - loader.NewFileLoaderAtRoot(fakeFs), nil, secrets) + loader.NewFileLoaderAtRoot(validators.MakeFakeValidator(), fakeFs), nil, secrets) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/pkg/target/kusttarget.go b/pkg/target/kusttarget.go index 06699f0ea..21a285548 100644 --- a/pkg/target/kusttarget.go +++ b/pkg/target/kusttarget.go @@ -144,7 +144,7 @@ func (kt *KustTarget) makeCustomizedResMap( rm := ra.ResMap() pt := kt.tFactory.MakeInventoryTransformer( - kt.kustomization.Inventory, + kt.kustomization.Inventory, kt.ldr, kt.kustomization.Namespace, garbagePolicy) err = pt.Transform(rm) diff --git a/pkg/target/plugindir_test.go b/pkg/target/plugindir_test.go index 5ff02de02..ec1c0cf0d 100644 --- a/pkg/target/plugindir_test.go +++ b/pkg/target/plugindir_test.go @@ -18,6 +18,7 @@ import ( "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/target" + "sigs.k8s.io/kustomize/pkg/validators" "sigs.k8s.io/kustomize/plugin" ) @@ -56,7 +57,8 @@ metadata: t.Fatalf("err %v", err) } - ldr, err := loader.NewLoader(loader.RestrictionRootOnly, dir, fSys) + ldr, err := loader.NewLoader( + loader.RestrictionRootOnly, validators.MakeFakeValidator(), dir, fSys) if err != nil { t.Fatalf("Err: %v", err) } diff --git a/pkg/transformers/config/factory_test.go b/pkg/transformers/config/factory_test.go index 04ad211d5..a3d797ba5 100644 --- a/pkg/transformers/config/factory_test.go +++ b/pkg/transformers/config/factory_test.go @@ -1,28 +1,14 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 package config import ( "reflect" - "sigs.k8s.io/kustomize/pkg/fs" - "sigs.k8s.io/kustomize/pkg/gvk" - "sigs.k8s.io/kustomize/pkg/ifc" - "sigs.k8s.io/kustomize/pkg/loader" "testing" + + "sigs.k8s.io/kustomize/internal/loadertest" + "sigs.k8s.io/kustomize/pkg/gvk" ) func TestMakeDefaultConfig(t *testing.T) { @@ -30,20 +16,15 @@ func TestMakeDefaultConfig(t *testing.T) { _ = MakeDefaultConfig() } -func makeTestLoader(path, content string) ifc.Loader { - fSys := fs.MakeFakeFS() - fSys.WriteFile(path, []byte(content)) - return loader.NewFileLoaderAtRoot(fSys) -} - func TestFromFiles(t *testing.T) { - path := "/transformerconfig/test/config.yaml" - ldr := makeTestLoader(path, ` + + ldr := loadertest.NewFakeLoader("/app") + ldr.AddFile("/app/config.yaml", []byte(` namePrefix: - path: nameprefix/path kind: SomeKind -`) - tcfg, err := NewFactory(ldr).FromFiles([]string{"transformerconfig/test/config.yaml"}) +`)) + tcfg, err := NewFactory(ldr).FromFiles([]string{"/app/config.yaml"}) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/pkg/types/kustomization.go b/pkg/types/kustomization.go index 5b9931b18..86fd1f985 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -242,6 +242,12 @@ type ConfigMapArgs struct { GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"` } +// Pair is a key value pair. +type Pair struct { + Key string + Value string +} + // SecretArgs contains the metadata of how to generate a secret. type SecretArgs struct { // GeneratorArgs for the secret. diff --git a/pkg/validators/validators.go b/pkg/validators/validators.go index 1be5c3df2..719f47611 100644 --- a/pkg/validators/validators.go +++ b/pkg/validators/validators.go @@ -1,18 +1,5 @@ -/* -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. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 // Package validators defines a FakeValidator that can be used in tests package validators @@ -48,6 +35,16 @@ func MakeFakeValidator() *FakeValidator { return &FakeValidator{} } +// ErrIfInvalidKey returns nil +func (v *FakeValidator) ErrIfInvalidKey(k string) error { + return nil +} + +// IsEnvVarName returns nil +func (v *FakeValidator) IsEnvVarName(k string) error { + return nil +} + // MakeAnnotationValidator returns a nil function func (v *FakeValidator) MakeAnnotationValidator() func(map[string]string) error { return nil diff --git a/plugin/someteam.example.com/v1/secretsfromdatabase/SecretsFromDatabase.go b/plugin/someteam.example.com/v1/secretsfromdatabase/SecretsFromDatabase.go index 38b12e43d..a1fcbbbaa 100644 --- a/plugin/someteam.example.com/v1/secretsfromdatabase/SecretsFromDatabase.go +++ b/plugin/someteam.example.com/v1/secretsfromdatabase/SecretsFromDatabase.go @@ -34,6 +34,7 @@ var database = map[string]string{ func (p *plugin) Config( ldr ifc.Loader, rf *resmap.Factory, c []byte) error { p.rf = rf + p.ldr = ldr return yaml.Unmarshal(c, p) }