From c9d903cc362a3db4deb6bfa73ff2f6740eeec9db Mon Sep 17 00:00:00 2001 From: Naeil ZOUEIDI Date: Thu, 23 May 2019 04:56:03 -0400 Subject: [PATCH 01/12] Add support for escaping characters in Doc --- examples/transformerconfigs/README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/transformerconfigs/README.md b/examples/transformerconfigs/README.md index 5b0cd7046..fd1c041ea 100644 --- a/examples/transformerconfigs/README.md +++ b/examples/transformerconfigs/README.md @@ -165,4 +165,14 @@ In addition to the default transformers, you can create custom transformer confi - [support a CRD type](crd/README.md) - add extra fields for variable substitution -- add extra fields for name reference \ No newline at end of file +- add extra fields for name reference + + +## Supporting escape characters in CRD path + +```yaml +metadata: + annotations: + foo.k8s.io/bar: baz +``` +Kustomize supports escaping special characters in path, e.g `matadata/annotations/foo.k8s.io\/bar` From e17d303392d46edc997ba581c2020ef5a80bdf83 Mon Sep 17 00:00:00 2001 From: Jingfang Liu Date: Thu, 23 May 2019 13:46:31 -0700 Subject: [PATCH 02/12] reorganize the examples layout --- examples/README.md | 81 ++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/examples/README.md b/examples/README.md index da4ec4b0b..1954fd60b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -12,46 +12,57 @@ tests, and should work with HEAD go get sigs.k8s.io/kustomize ``` - * [hello world](helloWorld/README.md) - Deploy multiple - (differently configured) variants of a simple Hello - World server. +Basic Usage - * [last mile helm](chart.md) - Make last mile modifications to - a helm chart. - - * [LDAP](ldap/README.md) - Deploy multiple - (differently configured) variants of a LDAP server. - - * [mySql](mySql/README.md) - Create a MySQL production - configuration from scratch. - - * [springboot](springboot/README.md) - Create a Spring Boot - application production configuration from scratch. - - * [combineConfigs](combineConfigs.md) - + * [configGenerations](configGeneration.md) - + Rolling update when ConfigMapGenerator changes. + + * [combineConfigs](combineConfigs.md) - Mixing configuration data from different owners (e.g. devops/SRE and developers). + + * [generatorOptions](generatorOptions.md) - + Modifying behavior of all ConfigMap and Secret generators. - * [configGenerations](configGeneration.md) - - Rolling update when ConfigMapGenerator changes. + * [vars](wordpress/README.md) - Injecting k8s runtime data into + container arguments (e.g. to point wordpress to a SQL service) by vars. + + * [image names and tags](image.md) - Updating image names and tags without applying a patch. + + * [remote target](remoteBuild.md) - Building a kustomization from a github URL + + * [json patch](jsonpatch.md) - Apply a json patch in a kustomization - * [secret generation](secretGeneratorPlugin.md) - Generating secrets from a plugin. +Advanced Usage + +- generator plugins: + + * [last mile helm](chart.md) - Make last mile modifications to + a helm chart. + + * [secret generation](secretGeneratorPlugin.md) - Generating secrets from a plugin. + +- customize builtin transformer configurations + + * [transformer configs](transformerconfigs/README.md) - Customize transformer configurations + - * [generatorOptions](generatorOptions.md) - - Modifying behavior of all ConfigMap and Secret generators. +Multi Variant Examples - * [breakfast](breakfast.md) - Customize breakfast for - Alice and Bob. + * [hello world](helloWorld/README.md) - Deploy multiple + (differently configured) variants of a simple Hello + World server. + + * [LDAP](ldap/README.md) - Deploy multiple + (differently configured) variants of a LDAP server. + + * [springboot](springboot/README.md) - Create a Spring Boot + application production configuration from scratch. - * [vars](wordpress/README.md) - Injecting k8s runtime data into - container arguments (e.g. to point wordpress to a SQL service) by vars. - - * [image names and tags](image.md) - Updating image names and tags without applying a patch. - - * [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base. - - * [remote target](remoteBuild.md) - Building a kustomization from a github URL - - * [json patch](jsonpatch.md) - Apply a json patch in a kustomization - - * [transformer configs](transformerconfigs/README.md) - Customize transformer configurations + * [mySql](mySql/README.md) - Create a MySQL production + configuration from scratch. + + * [breakfast](breakfast.md) - Customize breakfast for + Alice and Bob. + + * [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base. \ No newline at end of file From 6a106546180b25592e3b977cde609ad0b3ca865b Mon Sep 17 00:00:00 2001 From: Jeffrey Regan Date: Fri, 24 May 2019 14:27:36 -0700 Subject: [PATCH 03/12] Delete the KV plugin code. --- docs/plugins.md | 5 +- examples/chart.md | 3 +- examples/secretGeneratorPlugin.md | 4 +- .../configmapfactory_test.go | 21 +--- k8sdeps/configmapandsecret/factory.go | 62 +---------- k8sdeps/configmapandsecret/factory_test.go | 100 +---------------- .../configmapandsecret/secretfactory_test.go | 21 +--- k8sdeps/kunstruct/factory.go | 36 +------ k8sdeps/kv/plugin/builtin/envfiles.go | 51 --------- k8sdeps/kv/plugin/builtin/files.go | 49 --------- k8sdeps/kv/plugin/builtin/literals.go | 39 ------- k8sdeps/kv/plugin/builtinplugin.go | 47 -------- k8sdeps/kv/plugin/goplugin.go | 94 ---------------- k8sdeps/kv/plugin/plugin.go | 28 ----- k8sdeps/kv/plugin/registry.go | 87 --------------- pkg/commands/build/build.go | 26 ++--- pkg/commands/commands.go | 39 +------ pkg/commands/edit/add/configmap.go | 45 +++----- pkg/commands/edit/add/configmap_test.go | 97 ++++++++--------- pkg/commands/edit/add/secret.go | 49 +++------ pkg/commands/edit/add/secret_test.go | 91 +++++++--------- pkg/kusttest/kusttestharness.go | 8 +- pkg/plugins/compiler.go | 3 +- pkg/plugins/config.go | 66 +++++++++--- pkg/plugins/execplugin_test.go | 3 +- pkg/plugins/loader.go | 22 +--- pkg/plugins/loader_test.go | 5 +- pkg/target/baseandoverlaysmall_test.go | 6 +- pkg/target/builtinplugins_test.go | 101 ------------------ pkg/target/generatoroptions_test.go | 86 +++++++-------- pkg/target/plugindir_test.go | 9 +- pkg/target/transformerplugin_test.go | 24 +++++ pkg/types/kustomization.go | 14 +-- 33 files changed, 278 insertions(+), 1063 deletions(-) delete mode 100644 k8sdeps/kv/plugin/builtin/envfiles.go delete mode 100644 k8sdeps/kv/plugin/builtin/files.go delete mode 100644 k8sdeps/kv/plugin/builtin/literals.go delete mode 100644 k8sdeps/kv/plugin/builtinplugin.go delete mode 100644 k8sdeps/kv/plugin/goplugin.go delete mode 100644 k8sdeps/kv/plugin/plugin.go delete mode 100644 k8sdeps/kv/plugin/registry.go delete mode 100644 pkg/target/builtinplugins_test.go diff --git a/docs/plugins.md b/docs/plugins.md index 86ab59048..e252efda8 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -173,13 +173,10 @@ transformers cannot be expected to be commutative. A `kustomize build` that tries to use plugins but omits the flag -_TODO: Change flag_ - -> `--enable_alpha_goplugins_accept_panic_risk` +> `--enable_alpha_plugins` will fail with a warning about plugin use. - Flag use is an opt-in acknowledging the absence of plugin provenance. It's meant to give pause to someone who blindly downloads a kustomization from diff --git a/examples/chart.md b/examples/chart.md index 99dd25562..483cdbc52 100644 --- a/examples/chart.md +++ b/examples/chart.md @@ -150,8 +150,7 @@ correct environment and flags for plugins: ``` function kustomizeIt { XDG_CONFIG_HOME=$DEMO_HOME \ - kustomize build \ - --enable_alpha_goplugins_accept_panic_risk \ + kustomize build --enable_alpha_plugins \ $DEMO_HOME/$1 } ``` diff --git a/examples/secretGeneratorPlugin.md b/examples/secretGeneratorPlugin.md index eee9ab42b..7f58f2fd2 100644 --- a/examples/secretGeneratorPlugin.md +++ b/examples/secretGeneratorPlugin.md @@ -201,9 +201,7 @@ can be found under `$DEMO_HOME`: ``` result=$( \ XDG_CONFIG_HOME=$DEMO_HOME \ - kustomize \ - --enable_alpha_goplugins_accept_panic_risk \ - build $DEMO_HOME ) + kustomize build --enable_alpha_plugins $DEMO_HOME ) echo "$result" # Spot check the result: test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=") diff --git a/k8sdeps/configmapandsecret/configmapfactory_test.go b/k8sdeps/configmapandsecret/configmapfactory_test.go index b13fb4588..a163d9031 100644 --- a/k8sdeps/configmapandsecret/configmapfactory_test.go +++ b/k8sdeps/configmapandsecret/configmapfactory_test.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 @@ -22,7 +9,6 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/types" @@ -143,9 +129,8 @@ func TestConstructConfigMap(t *testing.T) { fSys.WriteFile("/configmap/app-init.ini", []byte("FOO=bar\nBAR=baz\n")) fSys.WriteFile("/configmap/app.bin", []byte{0xff, 0xfd}) ldr := loader.NewFileLoaderAtRoot(fSys) - reg := plugin.NewRegistry(ldr) for _, tc := range testCases { - f := NewFactory(ldr, tc.options, reg) + f := NewFactory(ldr, tc.options) cm, err := f.MakeConfigMap(&tc.input) if err != nil { t.Fatalf("unexpected error: %v", err) diff --git a/k8sdeps/configmapandsecret/factory.go b/k8sdeps/configmapandsecret/factory.go index 2c67e4386..c52fcf04c 100644 --- a/k8sdeps/configmapandsecret/factory.go +++ b/k8sdeps/configmapandsecret/factory.go @@ -1,30 +1,15 @@ -/* -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 configmapandsecret import ( "fmt" - "sort" "strings" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/util/validation" "sigs.k8s.io/kustomize/k8sdeps/kv" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/types" ) @@ -33,25 +18,17 @@ import ( type Factory struct { ldr ifc.Loader options *types.GeneratorOptions - reg plugin.Registry } // NewFactory returns a new Factory. func NewFactory( - l ifc.Loader, o *types.GeneratorOptions, reg plugin.Registry) *Factory { - return &Factory{ldr: l, options: o, reg: reg} + 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.keyValuesFromPlugins(args.KVSources) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf( - "plugins: %s", - args.KVSources)) - } - all = append(all, pairs...) - pairs, err = f.keyValuesFromEnvFiles(args.EnvSources) + pairs, err := f.keyValuesFromEnvFiles(args.EnvSources) if err != nil { return nil, errors.Wrap(err, fmt.Sprintf( "env source files: %v", @@ -96,35 +73,6 @@ func keyValuesFromLiteralSources(sources []string) ([]kv.Pair, error) { return kvs, nil } -func (f *Factory) keyValuesFromPlugins(sources []types.KVSource) ([]kv.Pair, error) { - var result []kv.Pair - for _, s := range sources { - plug, err := f.reg.Load(s.PluginType, s.Name) - if err != nil { - return nil, err - } - kvs, err := plug.Get(f.reg.Root(), s.Args) - if err != nil { - return nil, err - } - for _, k := range sortedKeys(kvs) { - result = append(result, kv.Pair{Key: k, Value: kvs[k]}) - } - } - return result, nil -} - -func sortedKeys(m map[string]string) []string { - keys := make([]string, len(m)) - i := 0 - for k := range m { - keys[i] = k - i++ - } - sort.Strings(keys) - return keys -} - func (f *Factory) keyValuesFromFileSources(sources []string) ([]kv.Pair, error) { var kvs []kv.Pair for _, s := range sources { diff --git a/k8sdeps/configmapandsecret/factory_test.go b/k8sdeps/configmapandsecret/factory_test.go index b11a57343..33891ce1b 100644 --- a/k8sdeps/configmapandsecret/factory_test.go +++ b/k8sdeps/configmapandsecret/factory_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 configmapandsecret @@ -21,10 +8,8 @@ import ( "testing" "sigs.k8s.io/kustomize/k8sdeps/kv" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/loader" - "sigs.k8s.io/kustomize/pkg/types" ) func TestKeyValuesFromFileSources(t *testing.T) { @@ -47,9 +32,7 @@ func TestKeyValuesFromFileSources(t *testing.T) { fSys := fs.MakeFakeFS() fSys.WriteFile("/files/app-init.ini", []byte("FOO=bar")) - ldr := loader.NewFileLoaderAtRoot(fSys) - reg := plugin.NewRegistry(ldr) - bf := NewFactory(loader.NewFileLoaderAtRoot(fSys), nil, reg) + bf := NewFactory(loader.NewFileLoaderAtRoot(fSys), nil) for _, tc := range tests { kvs, err := bf.keyValuesFromFileSources(tc.sources) if err != nil { @@ -60,80 +43,3 @@ func TestKeyValuesFromFileSources(t *testing.T) { } } } - -func TestKeyValuesFromPlugins(t *testing.T) { - tests := []struct { - description string - sources []types.KVSource - expected []kv.Pair - }{ - { - description: "Create kv.Pairs from builtin literals plugin", - sources: []types.KVSource{ - { - PluginType: "builtin", - Name: "literals", - Args: []string{"FOO=bar", "BAR=baz"}, - }, - }, - expected: []kv.Pair{ - { - Key: "BAR", - Value: "baz", - }, - { - Key: "FOO", - Value: "bar", - }, - }, - }, - { - description: "Create kv.Pairs from builtin files plugin", - sources: []types.KVSource{ - { - PluginType: "builtin", - Name: "files", - Args: []string{"files/app-init.ini"}, - }, - }, - expected: []kv.Pair{ - { - Key: "app-init.ini", - Value: "FOO=bar", - }, - }, - }, - { - description: "Create kv.Pairs from builtin envfiles plugin", - sources: []types.KVSource{ - { - PluginType: "builtin", - Name: "envfiles", - Args: []string{"files/app-init.ini"}, - }, - }, - expected: []kv.Pair{ - { - Key: "FOO", - Value: "bar", - }, - }, - }, - } - - fSys := fs.MakeFakeFS() - fSys.WriteFile("/files/app-init.ini", []byte("FOO=bar")) - ldr := loader.NewFileLoaderAtRoot(fSys) - reg := plugin.NewRegistry(ldr) - bf := NewFactory(ldr, nil, reg) - - for _, tc := range tests { - kvs, err := bf.keyValuesFromPlugins(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_test.go b/k8sdeps/configmapandsecret/secretfactory_test.go index 703de4257..b1e29fd4a 100644 --- a/k8sdeps/configmapandsecret/secretfactory_test.go +++ b/k8sdeps/configmapandsecret/secretfactory_test.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 @@ -22,7 +9,6 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/types" @@ -140,9 +126,8 @@ func TestConstructSecret(t *testing.T) { 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) - reg := plugin.NewRegistry(ldr) for _, tc := range testCases { - f := NewFactory(ldr, tc.options, reg) + f := NewFactory(ldr, tc.options) cm, err := f.MakeSecret(&tc.input) if err != nil { t.Fatalf("unexpected error: %v", err) diff --git a/k8sdeps/kunstruct/factory.go b/k8sdeps/kunstruct/factory.go index 4cd945932..a2a2b3479 100644 --- a/k8sdeps/kunstruct/factory.go +++ b/k8sdeps/kunstruct/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 kunstruct @@ -25,28 +12,19 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/yaml" "sigs.k8s.io/kustomize/k8sdeps/configmapandsecret" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/types" ) // KunstructuredFactoryImpl hides construction using apimachinery types. type KunstructuredFactoryImpl struct { - generatorMetaArgs *types.GeneratorMetaArgs } var _ ifc.KunstructuredFactory = &KunstructuredFactoryImpl{} // NewKunstructuredFactoryImpl returns a factory. func NewKunstructuredFactoryImpl() ifc.KunstructuredFactory { - return NewKunstructuredFactoryWithGeneratorArgs( - &types.GeneratorMetaArgs{}) -} - -// NewKunstructuredFactoryWithGeneratorArgs returns a factory. -func NewKunstructuredFactoryWithGeneratorArgs( - gma *types.GeneratorMetaArgs) ifc.KunstructuredFactory { - return &KunstructuredFactoryImpl{gma} + return &KunstructuredFactoryImpl{} } // SliceFromBytes returns a slice of Kunstructured. @@ -91,9 +69,7 @@ func (kf *KunstructuredFactoryImpl) MakeConfigMap( options *types.GeneratorOptions, args *types.ConfigMapArgs) (ifc.Kunstructured, error) { o, err := configmapandsecret.NewFactory( - ldr, options, - plugin.NewConfiguredRegistry( - ldr, kf.generatorMetaArgs.PluginConfig)).MakeConfigMap(args) + ldr, options).MakeConfigMap(args) if err != nil { return nil, err } @@ -106,9 +82,7 @@ func (kf *KunstructuredFactoryImpl) MakeSecret( options *types.GeneratorOptions, args *types.SecretArgs) (ifc.Kunstructured, error) { o, err := configmapandsecret.NewFactory( - ldr, options, - plugin.NewConfiguredRegistry( - ldr, kf.generatorMetaArgs.PluginConfig)).MakeSecret(args) + ldr, options).MakeSecret(args) if err != nil { return nil, err } diff --git a/k8sdeps/kv/plugin/builtin/envfiles.go b/k8sdeps/kv/plugin/builtin/envfiles.go deleted file mode 100644 index 816464f4f..000000000 --- a/k8sdeps/kv/plugin/builtin/envfiles.go +++ /dev/null @@ -1,51 +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 builtin - -import ( - "sigs.k8s.io/kustomize/k8sdeps/kv" - "sigs.k8s.io/kustomize/pkg/ifc" -) - -// EnvFiles format should be a path to a file to read lines of key=val -// pairs to create a configmap. -// i.e. a Docker .env file or a .ini file. -type EnvFiles struct { - Ldr ifc.Loader -} - -// Get implements the interface for kv plugins. -func (p EnvFiles) Get(root string, args []string) (map[string]string, error) { - all := make(map[string]string) - for _, path := range args { - if path == "" { - return nil, nil - } - content, err := p.Ldr.Load(path) - if err != nil { - return nil, err - } - kvs, err := kv.KeyValuesFromLines(content) - if err != nil { - return nil, err - } - for _, pair := range kvs { - all[pair.Key] = pair.Value - } - } - return all, nil -} diff --git a/k8sdeps/kv/plugin/builtin/files.go b/k8sdeps/kv/plugin/builtin/files.go deleted file mode 100644 index 626dfb88c..000000000 --- a/k8sdeps/kv/plugin/builtin/files.go +++ /dev/null @@ -1,49 +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 builtin - -import ( - "sigs.k8s.io/kustomize/k8sdeps/kv" - "sigs.k8s.io/kustomize/pkg/ifc" -) - -// Files is a list of file sources. -// Each file source can be specified using its file path, in which case file -// basename will be used as configmap key, or optionally with a key and file -// path, in which case the given key will be used. -// Specifying a directory will iterate each named file in the directory -// whose basename is a valid configmap key. -type Files struct { - Ldr ifc.Loader -} - -// Get implements the interface for kv plugins. -func (p Files) Get(root string, args []string) (map[string]string, error) { - kvs := make(map[string]string) - for _, s := range args { - k, fPath, err := kv.ParseFileSource(s) - if err != nil { - return nil, err - } - content, err := p.Ldr.Load(fPath) - if err != nil { - return nil, err - } - kvs[k] = string(content) - } - return kvs, nil -} diff --git a/k8sdeps/kv/plugin/builtin/literals.go b/k8sdeps/kv/plugin/builtin/literals.go deleted file mode 100644 index 364c1e8ff..000000000 --- a/k8sdeps/kv/plugin/builtin/literals.go +++ /dev/null @@ -1,39 +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 builtin - -import ( - "sigs.k8s.io/kustomize/k8sdeps/kv" -) - -// Literals takes a list of literals. -// Each literal source should be a key and literal value, -// e.g. `somekey=somevalue` -type Literals struct{} - -// Get implements the interface for kv plugins. -func (p Literals) Get(root string, args []string) (map[string]string, error) { - kvs := make(map[string]string) - for _, s := range args { - k, v, err := kv.ParseLiteralSource(s) - if err != nil { - return nil, err - } - kvs[k] = v - } - return kvs, nil -} diff --git a/k8sdeps/kv/plugin/builtinplugin.go b/k8sdeps/kv/plugin/builtinplugin.go deleted file mode 100644 index 225de4d40..000000000 --- a/k8sdeps/kv/plugin/builtinplugin.go +++ /dev/null @@ -1,47 +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 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(ldr ifc.Loader) *builtinFactory { - return &builtinFactory{ - plugins: map[string]KVSource{ - "literals": builtin.Literals{}, - "files": builtin.Files{Ldr: ldr}, - "envfiles": builtin.EnvFiles{Ldr: ldr}, - }, - } -} - -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/goplugin.go b/k8sdeps/kv/plugin/goplugin.go deleted file mode 100644 index a4970f75f..000000000 --- a/k8sdeps/kv/plugin/goplugin.go +++ /dev/null @@ -1,94 +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 plugin - -import ( - "fmt" - "path/filepath" - "plugin" - - "sigs.k8s.io/kustomize/pkg/types" -) - -var _ Factory = &goFactory{} - -const ( - kvSourcesDir = "kvSources" - EnableGoPluginsFlagName = "enable_alpha_goplugins_accept_panic_risk" - EnableGoPluginsFlagHelp = `The main program may panic and exit on an attempt -to use a goplugin that was compiled under conditions -differing from the those in effect when main was -compiled. It's safest to use this flag in the -context of a container image holding both the main -and the goplugins it needs, all built on the same -machine, with the same transitive libs and the same -compiler version.` - errorFmt = ` -enable go plugins by specifying flag - --%s -Place .so files in - %s -%s` -) - -func newGoFactory(c *types.PluginConfig) *goFactory { - return &goFactory{ - config: c, - plugins: make(map[string]KVSource), - } -} - -type goFactory struct { - config *types.PluginConfig - plugins map[string]KVSource -} - -func (p *goFactory) load(name string) (KVSource, error) { - if plug, ok := p.plugins[name]; ok { - return plug, nil - } - - dir := filepath.Join( - p.config.DirectoryPath, - kvSourcesDir) - if !p.config.GoEnabled { - return nil, fmt.Errorf( - errorFmt, - EnableGoPluginsFlagName, - dir, - EnableGoPluginsFlagHelp) - } - - goPlugin, err := plugin.Open( - filepath.Join(dir, name+".so")) - if err != nil { - return nil, err - } - - symbol, err := goPlugin.Lookup("KVSource") - if err != nil { - return nil, err - } - - plug, ok := symbol.(KVSource) - if !ok { - return nil, fmt.Errorf("plugin %s not found", name) - } - - p.plugins[name] = plug - return plug, nil -} diff --git a/k8sdeps/kv/plugin/plugin.go b/k8sdeps/kv/plugin/plugin.go deleted file mode 100644 index 29975999b..000000000 --- a/k8sdeps/kv/plugin/plugin.go +++ /dev/null @@ -1,28 +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 plugin provides a plugin abstraction layer. -package plugin - -// KVSource is the interface for kv source plugins. -type KVSource interface { - Get(root string, args []string) (map[string]string, error) -} - -// Factory is the interface for new kv source plugin implementations. -type Factory interface { - load(string) (KVSource, error) -} diff --git a/k8sdeps/kv/plugin/registry.go b/k8sdeps/kv/plugin/registry.go deleted file mode 100644 index adadedcd4..000000000 --- a/k8sdeps/kv/plugin/registry.go +++ /dev/null @@ -1,87 +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 plugin - -import ( - "fmt" - "path/filepath" - - "sigs.k8s.io/kustomize/pkg/ifc" - "sigs.k8s.io/kustomize/pkg/pgmconfig" - "sigs.k8s.io/kustomize/pkg/types" -) - -// Registry holds all the plugin factories. -type Registry struct { - factories map[types.PluginType]Factory - ldr ifc.Loader -} - -const ( - pluginTypeGo = types.PluginType("go") - pluginTypeBuiltIn = types.PluginType("builtin") -) - -func ActivePluginConfig() *types.PluginConfig { - pc := DefaultPluginConfig() - pc.GoEnabled = true - return pc -} - -func DefaultPluginConfig() *types.PluginConfig { - return &types.PluginConfig{ - GoEnabled: false, - DirectoryPath: filepath.Join( - pgmconfig.ConfigRoot(), pgmconfig.PluginRoot), - } -} - -// NewConfiguredRegistry returns a new Registry loaded -// with all the factories and a custom PluginConfig. -func NewConfiguredRegistry( - ldr ifc.Loader, pc *types.PluginConfig) Registry { - return Registry{ - ldr: ldr, - factories: map[types.PluginType]Factory{ - pluginTypeGo: newGoFactory(pc), - pluginTypeBuiltIn: newBuiltinFactory(ldr), - }, - } -} - -// NewRegistry returns a new Registry with default config. -func NewRegistry(ldr ifc.Loader) Registry { - return NewConfiguredRegistry(ldr, &types.PluginConfig{}) -} - -// Load returns a plugin by type and name. -func (r *Registry) Load( - pt types.PluginType, name string) (KVSource, error) { - if pt.IsUndefined() { - pt = pluginTypeBuiltIn - } - factory, exists := r.factories[pt] - if !exists { - return nil, fmt.Errorf("%s is not a valid plugin type", pt) - } - return factory.load(name) -} - -// Root returns the root of the plugins kustomization file. -func (r *Registry) Root() string { - return r.ldr.Root() -} diff --git a/pkg/commands/build/build.go b/pkg/commands/build/build.go index 05fcd2896..95d2f7cb8 100644 --- a/pkg/commands/build/build.go +++ b/pkg/commands/build/build.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 build @@ -69,10 +56,12 @@ url examples: func NewCmdBuild( out io.Writer, fs fs.FileSystem, rf *resmap.Factory, - ptf transformer.Factory, - pl *plugins.Loader) *cobra.Command { + ptf transformer.Factory) *cobra.Command { var o Options + pluginConfig := plugins.DefaultPluginConfig() + pl := plugins.NewLoader(pluginConfig, rf) + cmd := &cobra.Command{ Use: "build [path]", Short: "Print current configuration per contents of " + pgmconfig.KustomizationFileNames[0], @@ -86,11 +75,14 @@ func NewCmdBuild( return o.RunBuild(out, fs, rf, ptf, pl) }, } + cmd.Flags().StringVarP( &o.outputPath, "output", "o", "", "If specified, write the build output to this path.") loader.AddLoadRestrictionsFlag(cmd.Flags()) + plugins.AddEnablePluginsFlag( + cmd.Flags(), &pluginConfig.Enabled) cmd.AddCommand(NewCmdBuildPrune(out, fs, rf, ptf, pl)) return cmd diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index e6396f554..782a9c07b 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.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 commands holds the CLI glue mapping textual commands/args to method calls. package commands @@ -23,7 +10,6 @@ import ( "github.com/spf13/cobra" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/k8sdeps/transformer" "sigs.k8s.io/kustomize/k8sdeps/validator" "sigs.k8s.io/kustomize/pkg/commands/build" @@ -31,10 +17,8 @@ import ( "sigs.k8s.io/kustomize/pkg/commands/misc" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/pgmconfig" - "sigs.k8s.io/kustomize/pkg/plugins" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" - "sigs.k8s.io/kustomize/pkg/types" ) // NewDefaultCommand returns the default (aka root) command for kustomize command. @@ -51,27 +35,12 @@ See https://sigs.k8s.io/kustomize `, } - pluginConfig := plugin.DefaultPluginConfig() - - c.PersistentFlags().BoolVar( - &pluginConfig.GoEnabled, - plugin.EnableGoPluginsFlagName, - false, plugin.EnableGoPluginsFlagHelp) - // Not advertising this alpha feature. - c.PersistentFlags().MarkHidden(plugin.EnableGoPluginsFlagName) - - // Configuration for ConfigMap and Secret generators. - genMetaArgs := types.GeneratorMetaArgs{ - PluginConfig: pluginConfig, - } - uf := kunstruct.NewKunstructuredFactoryWithGeneratorArgs(&genMetaArgs) + uf := kunstruct.NewKunstructuredFactoryImpl() rf := resmap.NewFactory(resource.NewFactory(uf)) c.AddCommand( build.NewCmdBuild( stdOut, fSys, - rf, - transformer.NewFactoryImpl(), - plugins.NewLoader(pluginConfig, rf)), + rf, transformer.NewFactoryImpl()), edit.NewCmdEdit(fSys, validator.NewKustValidator(), uf), misc.NewCmdConfig(fSys), misc.NewCmdVersion(stdOut), diff --git a/pkg/commands/edit/add/configmap.go b/pkg/commands/edit/add/configmap.go index 5e8361bdc..5e2e3924a 100644 --- a/pkg/commands/edit/add/configmap.go +++ b/pkg/commands/edit/add/configmap.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 @@ -104,17 +91,17 @@ func addConfigMap( ldr ifc.Loader, k *types.Kustomization, flags flagsAndArgs, kf ifc.KunstructuredFactory) error { - cmArgs := makeConfigMapArgs(k, flags.Name) - mergeFlagsIntoCmArgs(&cmArgs.KVSources, flags) + args := findOrMakeConfigMapArgs(k, flags.Name) + mergeFlagsIntoCmArgs(args, flags) // Validate by trying to create corev1.configmap. - _, err := kf.MakeConfigMap(ldr, k.GeneratorOptions, cmArgs) + _, err := kf.MakeConfigMap(ldr, k.GeneratorOptions, args) if err != nil { return err } return nil } -func makeConfigMapArgs(m *types.Kustomization, name string) *types.ConfigMapArgs { +func findOrMakeConfigMapArgs(m *types.Kustomization, name string) *types.ConfigMapArgs { for i, v := range m.ConfigMapGenerator { if name == v.Name { return &m.ConfigMapGenerator[i] @@ -126,23 +113,17 @@ func makeConfigMapArgs(m *types.Kustomization, name string) *types.ConfigMapArgs return &m.ConfigMapGenerator[len(m.ConfigMapGenerator)-1] } -func mergeFlagsIntoCmArgs(src *[]types.KVSource, flags flagsAndArgs) { +func mergeFlagsIntoCmArgs(args *types.ConfigMapArgs, flags flagsAndArgs) { if len(flags.LiteralSources) > 0 { - *src = append(*src, types.KVSource{ - Name: "literals", - Args: flags.LiteralSources, - }) + args.LiteralSources = append( + args.LiteralSources, flags.LiteralSources...) } if len(flags.FileSources) > 0 { - *src = append(*src, types.KVSource{ - Name: "files", - Args: flags.FileSources, - }) + args.FileSources = append( + args.FileSources, flags.FileSources...) } if flags.EnvFileSource != "" { - *src = append(*src, types.KVSource{ - Name: "envfiles", - Args: []string{flags.EnvFileSource}, - }) + args.EnvSources = append( + args.EnvSources, flags.EnvFileSource) } } diff --git a/pkg/commands/edit/add/configmap_test.go b/pkg/commands/edit/add/configmap_test.go index 2aaa99e8f..5b1b2d7e7 100644 --- a/pkg/commands/edit/add/configmap_test.go +++ b/pkg/commands/edit/add/configmap_test.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 @@ -39,7 +26,7 @@ func TestMakeConfigMapArgs(t *testing.T) { if len(kustomization.ConfigMapGenerator) != 0 { t.Fatal("Initial kustomization should not have any configmaps") } - args := makeConfigMapArgs(kustomization, cmName) + args := findOrMakeConfigMapArgs(kustomization, cmName) if args == nil { t.Fatalf("args should always be non-nil") @@ -53,7 +40,7 @@ func TestMakeConfigMapArgs(t *testing.T) { t.Fatalf("Pointer address for newly inserted configmap generator should be same") } - args2 := makeConfigMapArgs(kustomization, cmName) + args2 := findOrMakeConfigMapArgs(kustomization, cmName) if args2 != args { t.Fatalf("should have returned an existing args with name: %v", cmName) @@ -64,51 +51,53 @@ func TestMakeConfigMapArgs(t *testing.T) { } } -func TestMergeFlagsIntoCmArgs_LiteralSources(t *testing.T) { - var kv []types.KVSource - - mergeFlagsIntoCmArgs(&kv, flagsAndArgs{LiteralSources: []string{"k1=v1"}}) - - if len(kv) != 1 { - t.Fatalf("Initial literal source should have been added") +func TestMergeFlagsIntoConfigMapArgs_LiteralSources(t *testing.T) { + k := &types.Kustomization{} + args := findOrMakeConfigMapArgs(k, "foo") + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{LiteralSources: []string{"k1=v1"}}) + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{LiteralSources: []string{"k2=v2"}}) + if k.ConfigMapGenerator[0].LiteralSources[0] != "k1=v1" { + t.Fatalf("expected v1") } - - mergeFlagsIntoCmArgs(&kv, flagsAndArgs{LiteralSources: []string{"k2=v2"}}) - - if len(kv) != 2 { - t.Fatalf("Second literal source should have been added") + if k.ConfigMapGenerator[0].LiteralSources[1] != "k2=v2" { + t.Fatalf("expected v2") } } -func TestMergeFlagsIntoCmArgs_FileSources(t *testing.T) { - var kv []types.KVSource - - mergeFlagsIntoCmArgs(&kv, flagsAndArgs{FileSources: []string{"file1"}}) - - if len(kv) != 1 { - t.Fatalf("Initial file source should have been added") +func TestMergeFlagsIntoConfigMapArgs_FileSources(t *testing.T) { + k := &types.Kustomization{} + args := findOrMakeConfigMapArgs(k, "foo") + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{FileSources: []string{"file1"}}) + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{FileSources: []string{"file2"}}) + if k.ConfigMapGenerator[0].FileSources[0] != "file1" { + t.Fatalf("expected file1") } - - mergeFlagsIntoCmArgs(&kv, flagsAndArgs{FileSources: []string{"file2"}}) - - if len(kv) != 2 { - t.Fatalf("Second file source should have been added") + if k.ConfigMapGenerator[0].FileSources[1] != "file2" { + t.Fatalf("expected file2") } } -func TestMergeFlagsIntoCmArgs_EnvSource(t *testing.T) { - envFileName := "env1" - envFileName2 := "env2" - var kv []types.KVSource - - mergeFlagsIntoCmArgs(&kv, flagsAndArgs{EnvFileSource: envFileName}) - - if len(kv) != 1 { - t.Fatalf("Initial env source should have been added") +func TestMergeFlagsIntoConfigMapArgs_EnvSource(t *testing.T) { + k := &types.Kustomization{} + args := findOrMakeConfigMapArgs(k, "foo") + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{EnvFileSource: "env1"}) + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{EnvFileSource: "env2"}) + if k.ConfigMapGenerator[0].EnvSources[0] != "env1" { + t.Fatalf("expected env1") } - - mergeFlagsIntoCmArgs(&kv, flagsAndArgs{EnvFileSource: envFileName2}) - if len(kv) != 2 { - t.Fatalf("Second env source should have been added") + if k.ConfigMapGenerator[0].EnvSources[1] != "env2" { + t.Fatalf("expected env2") } } diff --git a/pkg/commands/edit/add/secret.go b/pkg/commands/edit/add/secret.go index aaaf2267b..8749f17d3 100644 --- a/pkg/commands/edit/add/secret.go +++ b/pkg/commands/edit/add/secret.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 add @@ -109,45 +96,41 @@ func addSecret( ldr ifc.Loader, k *types.Kustomization, flags flagsAndArgs, kf ifc.KunstructuredFactory) error { - secretArgs := makeSecretArgs(k, flags.Name, flags.Type) - mergeFlagsIntoSecretArgs(&secretArgs.KVSources, flags) + args := findOrMakeSecretArgs(k, flags.Name, flags.Type) + mergeFlagsIntoGeneratorArgs(&args.GeneratorArgs, flags) // Validate by trying to create corev1.secret. - _, err := kf.MakeSecret(ldr, k.GeneratorOptions, secretArgs) + _, err := kf.MakeSecret(ldr, k.GeneratorOptions, args) if err != nil { return err } return nil } -func makeSecretArgs(m *types.Kustomization, name, secretType string) *types.SecretArgs { +func findOrMakeSecretArgs(m *types.Kustomization, name, secretType string) *types.SecretArgs { for i, v := range m.SecretGenerator { if name == v.Name { return &m.SecretGenerator[i] } } // secret not found, create new one and add it to the kustomization file. - secret := &types.SecretArgs{GeneratorArgs: types.GeneratorArgs{Name: name}, Type: secretType} + secret := &types.SecretArgs{ + GeneratorArgs: types.GeneratorArgs{Name: name}, + Type: secretType} m.SecretGenerator = append(m.SecretGenerator, *secret) return &m.SecretGenerator[len(m.SecretGenerator)-1] } -func mergeFlagsIntoSecretArgs(src *[]types.KVSource, flags flagsAndArgs) { +func mergeFlagsIntoGeneratorArgs(args *types.GeneratorArgs, flags flagsAndArgs) { if len(flags.LiteralSources) > 0 { - *src = append(*src, types.KVSource{ - Name: "literals", - Args: flags.LiteralSources, - }) + args.LiteralSources = append( + args.LiteralSources, flags.LiteralSources...) } if len(flags.FileSources) > 0 { - *src = append(*src, types.KVSource{ - Name: "files", - Args: flags.FileSources, - }) + args.FileSources = append( + args.FileSources, flags.FileSources...) } if flags.EnvFileSource != "" { - *src = append(*src, types.KVSource{ - Name: "envfiles", - Args: []string{flags.EnvFileSource}, - }) + args.EnvSources = append( + args.EnvSources, flags.EnvFileSource) } } diff --git a/pkg/commands/edit/add/secret_test.go b/pkg/commands/edit/add/secret_test.go index 476e48ac1..6df3f90dd 100644 --- a/pkg/commands/edit/add/secret_test.go +++ b/pkg/commands/edit/add/secret_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 add @@ -41,7 +28,7 @@ func TestMakeSecretArgs(t *testing.T) { if len(kustomization.SecretGenerator) != 0 { t.Fatal("Initial kustomization should not have any secrets") } - args := makeSecretArgs(kustomization, secretName, secretType) + args := findOrMakeSecretArgs(kustomization, secretName, secretType) if args == nil { t.Fatalf("args should always be non-nil") @@ -55,7 +42,7 @@ func TestMakeSecretArgs(t *testing.T) { t.Fatalf("Pointer address for newly inserted secret generator should be same") } - args2 := makeSecretArgs(kustomization, secretName, secretType) + args2 := findOrMakeSecretArgs(kustomization, secretName, secretType) if args2 != args { t.Fatalf("should have returned an existing args with name: %v", secretName) @@ -67,50 +54,52 @@ func TestMakeSecretArgs(t *testing.T) { } func TestMergeFlagsIntoSecretArgs_LiteralSources(t *testing.T) { - var kv []types.KVSource - - mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{LiteralSources: []string{"k1=v1"}}) - - if len(kv) != 1 { - t.Fatalf("Initial literal source should have been added") + k := &types.Kustomization{} + args := findOrMakeSecretArgs(k, "foo", "forbidden") + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{LiteralSources: []string{"k1=v1"}}) + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{LiteralSources: []string{"k2=v2"}}) + if k.SecretGenerator[0].LiteralSources[0] != "k1=v1" { + t.Fatalf("expected v1") } - - mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{LiteralSources: []string{"k2=v2"}}) - - if len(kv) != 2 { - t.Fatalf("Second literal source should have been added") + if k.SecretGenerator[0].LiteralSources[1] != "k2=v2" { + t.Fatalf("expected v2") } } func TestMergeFlagsIntoSecretArgs_FileSources(t *testing.T) { - var kv []types.KVSource - - mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{FileSources: []string{"file1"}}) - - if len(kv) != 1 { - t.Fatalf("Initial file source should have been added") + k := &types.Kustomization{} + args := findOrMakeSecretArgs(k, "foo", "forbidden") + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{FileSources: []string{"file1"}}) + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{FileSources: []string{"file2"}}) + if k.SecretGenerator[0].FileSources[0] != "file1" { + t.Fatalf("expected file1") } - - mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{FileSources: []string{"file2"}}) - - if len(kv) != 2 { - t.Fatalf("Second file source should have been added") + if k.SecretGenerator[0].FileSources[1] != "file2" { + t.Fatalf("expected file2") } } func TestMergeFlagsIntoSecretArgs_EnvSource(t *testing.T) { - envFileName := "env1" - envFileName2 := "env2" - var kv []types.KVSource - - mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{EnvFileSource: envFileName}) - - if len(kv) != 1 { - t.Fatalf("Initial env source should have been added") + k := &types.Kustomization{} + args := findOrMakeSecretArgs(k, "foo", "forbidden") + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{EnvFileSource: "env1"}) + mergeFlagsIntoGeneratorArgs( + &args.GeneratorArgs, + flagsAndArgs{EnvFileSource: "env2"}) + if k.SecretGenerator[0].EnvSources[0] != "env1" { + t.Fatalf("expected env1") } - - mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{EnvFileSource: envFileName2}) - if len(kv) != 2 { - t.Fatalf("Second env source should have been added") + if k.SecretGenerator[0].EnvSources[1] != "env2" { + t.Fatalf("expected env2") } } diff --git a/pkg/kusttest/kusttestharness.go b/pkg/kusttest/kusttestharness.go index c22c93841..fa10aa645 100644 --- a/pkg/kusttest/kusttestharness.go +++ b/pkg/kusttest/kusttestharness.go @@ -11,7 +11,6 @@ import ( "sigs.k8s.io/kustomize/internal/loadertest" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/k8sdeps/transformer" "sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/pgmconfig" @@ -33,12 +32,12 @@ type KustTestHarness struct { func NewKustTestHarness(t *testing.T, path string) *KustTestHarness { return NewKustTestHarnessWithPluginConfig( - t, path, plugin.DefaultPluginConfig()) + t, path, plugins.DefaultPluginConfig()) } func NewKustTestPluginHarness(t *testing.T, path string) *KustTestHarness { return NewKustTestHarnessWithPluginConfig( - t, path, plugin.ActivePluginConfig()) + t, path, plugins.ActivePluginConfig()) } func NewKustTestHarnessWithPluginConfig( @@ -51,8 +50,7 @@ func NewKustTestHarnessFull( t *testing.T, path string, lr loader.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness { rf := resmap.NewFactory(resource.NewFactory( - kunstruct.NewKunstructuredFactoryWithGeneratorArgs( - &types.GeneratorMetaArgs{PluginConfig: pc}))) + kunstruct.NewKunstructuredFactoryImpl())) return &KustTestHarness{ t: t, rf: rf, diff --git a/pkg/plugins/compiler.go b/pkg/plugins/compiler.go index 601b45065..2ae69507e 100644 --- a/pkg/plugins/compiler.go +++ b/pkg/plugins/compiler.go @@ -24,7 +24,6 @@ import ( "strings" "time" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/pgmconfig" ) @@ -56,7 +55,7 @@ func DefaultSrcRoot() (string, error) { } nope = append(nope, root) - root = plugin.DefaultPluginConfig().DirectoryPath + root = DefaultPluginConfig().DirectoryPath if FileExists(root) { return root, nil } diff --git a/pkg/plugins/config.go b/pkg/plugins/config.go index 24c94ba65..aea287dbd 100644 --- a/pkg/plugins/config.go +++ b/pkg/plugins/config.go @@ -1,19 +1,53 @@ -/* -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 plugins -const PluginSymbol = "KustomizePlugin" +import ( + "fmt" + "github.com/spf13/pflag" + "path/filepath" + "sigs.k8s.io/kustomize/pkg/pgmconfig" + "sigs.k8s.io/kustomize/pkg/types" +) + +const ( + PluginSymbol = "KustomizePlugin" + 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 +specify the flag + --%s +to %s` +) + +func ActivePluginConfig() *types.PluginConfig { + pc := DefaultPluginConfig() + pc.Enabled = true + return pc +} + +func DefaultPluginConfig() *types.PluginConfig { + return &types.PluginConfig{ + Enabled: false, + DirectoryPath: filepath.Join( + pgmconfig.ConfigRoot(), pgmconfig.PluginRoot), + } +} + +func PluginsNotEnabledErr(name string) error { + return fmt.Errorf( + flagErrorFmt, + name, + flagEnablePluginsName, + flagEnablePluginsHelp) +} + +func AddEnablePluginsFlag(set *pflag.FlagSet, v *bool) { + set.BoolVar( + v, flagEnablePluginsName, + false, flagEnablePluginsHelp) +} diff --git a/pkg/plugins/execplugin_test.go b/pkg/plugins/execplugin_test.go index 2b0daf8ad..ac04cd5ac 100644 --- a/pkg/plugins/execplugin_test.go +++ b/pkg/plugins/execplugin_test.go @@ -22,7 +22,6 @@ import ( "sigs.k8s.io/kustomize/internal/loadertest" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" ) @@ -52,7 +51,7 @@ s/$BAR/bar/g p := NewExecPlugin( AbsolutePluginPath( - plugin.DefaultPluginConfig(), + DefaultPluginConfig(), pluginConfig.Id())) yaml, err := pluginConfig.AsYAML() diff --git a/pkg/plugins/loader.go b/pkg/plugins/loader.go index c5ef29ce0..97509a2ff 100644 --- a/pkg/plugins/loader.go +++ b/pkg/plugins/loader.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 plugins @@ -115,9 +102,8 @@ 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.GoEnabled { - return nil, errors.Errorf( - "plugins not enabled, but trying to load %s", res.Id()) + if !l.pc.Enabled { + return nil, PluginsNotEnabledErr(res.Id().Gvk().Kind) } if p := NewExecPlugin( l.absolutePluginPath(res.Id())); p.isAvailable() { diff --git a/pkg/plugins/loader_test.go b/pkg/plugins/loader_test.go index 69d12626a..89b30fbf2 100644 --- a/pkg/plugins/loader_test.go +++ b/pkg/plugins/loader_test.go @@ -8,8 +8,7 @@ import ( "sigs.k8s.io/kustomize/internal/loadertest" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" - kvplugin "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" - "sigs.k8s.io/kustomize/pkg/plugins" + . "sigs.k8s.io/kustomize/pkg/plugins" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/plugin" @@ -54,7 +53,7 @@ func TestLoader(t *testing.T) { rmF := resmap.NewFactory(resource.NewFactory( kunstruct.NewKunstructuredFactoryImpl())) - l := plugins.NewLoader(kvplugin.ActivePluginConfig(), rmF) + l := NewLoader(ActivePluginConfig(), rmF) if l == nil { t.Fatal("expect non-nil loader") } diff --git a/pkg/target/baseandoverlaysmall_test.go b/pkg/target/baseandoverlaysmall_test.go index 3bbf12996..c06f9c4a3 100644 --- a/pkg/target/baseandoverlaysmall_test.go +++ b/pkg/target/baseandoverlaysmall_test.go @@ -17,10 +17,10 @@ limitations under the License. package target_test import ( + "sigs.k8s.io/kustomize/pkg/plugins" "strings" "testing" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/kusttest" "sigs.k8s.io/kustomize/pkg/loader" ) @@ -225,7 +225,7 @@ spec: func TestSharedPatchDisAllowed(t *testing.T) { th := kusttest_test.NewKustTestHarnessFull( t, "/app/overlay", - loader.RestrictionRootOnly, plugin.DefaultPluginConfig()) + loader.RestrictionRootOnly, plugins.DefaultPluginConfig()) writeSmallBase(th) th.WriteK("/app/overlay", ` commonLabels: @@ -257,7 +257,7 @@ spec: func TestSharedPatchAllowed(t *testing.T) { th := kusttest_test.NewKustTestHarnessFull( t, "/app/overlay", - loader.RestrictionNone, plugin.DefaultPluginConfig()) + loader.RestrictionNone, plugins.DefaultPluginConfig()) writeSmallBase(th) th.WriteK("/app/overlay", ` commonLabels: diff --git a/pkg/target/builtinplugins_test.go b/pkg/target/builtinplugins_test.go deleted file mode 100644 index c7a190cd7..000000000 --- a/pkg/target/builtinplugins_test.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 target_test - -import ( - "testing" - - "sigs.k8s.io/kustomize/pkg/kusttest" -) - -const result = ` -apiVersion: v1 -data: - FRUIT: YXBwbGU= - MOUNTAIN: ZXZlcmVzdA== - OCEAN: cGFjaWZpYw== - VEGETABLE: Y2Fycm90 - foo.env: Ck1PVU5UQUlOPWV2ZXJlc3QKT0NFQU49cGFjaWZpYwo= - passphrase: ZGF0IHBocmFzZQ== -kind: Secret -metadata: - name: bob-kf5c9fccbt -type: Opaque -` - -func writeDataFiles(th *kusttest_test.KustTestHarness) { - th.WriteF("/app/foo.env", ` -MOUNTAIN=everest -OCEAN=pacific -`) - th.WriteF("/app/phrase.dat", "dat phrase") -} - -func TestBuiltinPlugins(t *testing.T) { - th := kusttest_test.NewKustTestHarness(t, "/app") - th.WriteK("/app", ` -secretGenerator: -- name: bob - kvSources: - - pluginType: builtin - name: literals - args: - - FRUIT=apple - - VEGETABLE=carrot - - pluginType: builtin - name: files - args: - - foo.env - - passphrase=phrase.dat - - pluginType: builtin - name: envfiles - args: - - foo.env -`) - writeDataFiles(th) - m, err := th.MakeKustTarget().MakeCustomizedResMap() - if err != nil { - t.Fatalf("Err: %v", err) - } - th.AssertActualEqualsExpected(m, result) -} - -func TestBuiltinIsTheDefault(t *testing.T) { - th := kusttest_test.NewKustTestHarness(t, "/app") - th.WriteK("/app", ` -secretGenerator: -- name: bob - kvSources: - - name: literals - args: - - FRUIT=apple - - VEGETABLE=carrot - - name: files - args: - - foo.env - - passphrase=phrase.dat - - name: envfiles - args: - - foo.env -`) - writeDataFiles(th) - m, err := th.MakeKustTarget().MakeCustomizedResMap() - if err != nil { - t.Fatalf("Err: %v", err) - } - th.AssertActualEqualsExpected(m, result) -} diff --git a/pkg/target/generatoroptions_test.go b/pkg/target/generatoroptions_test.go index 80eb85d03..b4a8ce578 100644 --- a/pkg/target/generatoroptions_test.go +++ b/pkg/target/generatoroptions_test.go @@ -17,14 +17,50 @@ limitations under the License. package target_test import ( - "path/filepath" - "strings" "testing" - "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/kusttest" ) +func TestSecretGenerator(t *testing.T) { + th := kusttest_test.NewKustTestHarness(t, "/app") + th.WriteK("/app", ` +secretGenerator: +- name: bob + literals: + - FRUIT=apple + - VEGETABLE=carrot + files: + - foo.env + - passphrase=phrase.dat + envs: + - foo.env +`) + th.WriteF("/app/foo.env", ` +MOUNTAIN=everest +OCEAN=pacific +`) + th.WriteF("/app/phrase.dat", "dat phrase") + m, err := th.MakeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.AssertActualEqualsExpected(m, ` +apiVersion: v1 +data: + FRUIT: YXBwbGU= + MOUNTAIN: ZXZlcmVzdA== + OCEAN: cGFjaWZpYw== + VEGETABLE: Y2Fycm90 + foo.env: Ck1PVU5UQUlOPWV2ZXJlc3QKT0NFQU49cGFjaWZpYwo= + passphrase: ZGF0IHBocmFzZQ== +kind: Secret +metadata: + name: bob-kf5c9fccbt +type: Opaque +`) +} + func TestGeneratorOptionsWithBases(t *testing.T) { th := kusttest_test.NewKustTestHarness(t, "/app/overlay") th.WriteK("/app/base", ` @@ -77,47 +113,3 @@ metadata: name: shouldNotHaveHash `) } - -func TestGoPluginNotEnabled(t *testing.T) { - th := kusttest_test.NewKustTestHarness(t, "/app") - th.WriteK("/app", ` -secretGenerator: -- name: attemptGoPlugin - kvSources: - - name: foo - pluginType: go - args: - - someArg - - someOtherArg -`) - _, err := th.MakeKustTarget().MakeCustomizedResMap() - if err == nil { - t.Fatalf("expected error") - } - if !strings.Contains(err.Error(), "enable go plugins by ") { - t.Fatalf("unexpected err: %v", err) - } -} - -func TestGoPluginDoesNotExist(t *testing.T) { - th := kusttest_test.NewKustTestHarnessWithPluginConfig( - t, "/app", plugin.ActivePluginConfig()) - th.WriteK("/app", ` -secretGenerator: -- name: attemptGoPlugin - kvSources: - - name: foo - pluginType: go - args: - - someArg - - someOtherArg -`) - _, err := th.MakeKustTarget().MakeCustomizedResMap() - if err == nil { - t.Fatalf("expected error") - } - if !strings.Contains(err.Error(), - filepath.Join("kvSources", "foo.so")) { - t.Fatalf("unexpected err: %v", err) - } -} diff --git a/pkg/target/plugindir_test.go b/pkg/target/plugindir_test.go index bb9b100b3..5ff02de02 100644 --- a/pkg/target/plugindir_test.go +++ b/pkg/target/plugindir_test.go @@ -10,7 +10,6 @@ import ( "testing" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" - kvplugin "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/k8sdeps/transformer" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/kusttest" @@ -19,7 +18,6 @@ import ( "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/target" - "sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/plugin" ) @@ -63,12 +61,9 @@ metadata: t.Fatalf("Err: %v", err) } rf := resmap.NewFactory(resource.NewFactory( - kunstruct.NewKunstructuredFactoryWithGeneratorArgs( - &types.GeneratorMetaArgs{ - PluginConfig: kvplugin.ActivePluginConfig(), - }))) + kunstruct.NewKunstructuredFactoryImpl())) - pl := plugins.NewLoader(kvplugin.ActivePluginConfig(), rf) + pl := plugins.NewLoader(plugins.ActivePluginConfig(), rf) tg, err := target.NewKustTarget(ldr, rf, transformer.NewFactoryImpl(), pl) if err != nil { t.Fatalf("err %v", err) diff --git a/pkg/target/transformerplugin_test.go b/pkg/target/transformerplugin_test.go index 530365fc0..520f846b6 100644 --- a/pkg/target/transformerplugin_test.go +++ b/pkg/target/transformerplugin_test.go @@ -4,6 +4,7 @@ package target_test import ( + "strings" "testing" "sigs.k8s.io/kustomize/pkg/kusttest" @@ -91,6 +92,29 @@ spec: `) } +func TestPluginsNotEnabled(t *testing.T) { + tc := plugin.NewEnvForTest(t).Set() + defer tc.Reset() + + tc.BuildGoPlugin( + "someteam.example.com", "v1", "StringPrefixer") + + th := kusttest_test.NewKustTestHarness(t, "/app") + th.WriteK("/app", ` +transformers: +- stringPrefixer.yaml +`) + writeStringPrefixer(th, "/app/stringPrefixer.yaml") + + _, err := th.MakeKustTarget().MakeCustomizedResMap() + if err == nil { + t.Fatalf("expected error") + } + if !strings.Contains(err.Error(), "unable to load plugin StringPrefixer") { + t.Fatalf("unexpected err: %v", err) + } +} + func TestSedTransformer(t *testing.T) { tc := plugin.NewEnvForTest(t).Set() defer tc.Reset() diff --git a/pkg/types/kustomization.go b/pkg/types/kustomization.go index 3bba41e2a..5b9931b18 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -222,15 +222,6 @@ type GeneratorArgs struct { // DataSources for the generator. DataSources `json:",inline,omitempty" yaml:",inline,omitempty"` - - // KVSources for the generator. - KVSources []KVSource `json:",inline,omitempty" yaml:",inline,omitempty"` -} - -// GeneratorMetaArgs contains arguments common to generators -// that come from somewhere other than a kustomization file. -type GeneratorMetaArgs struct { - PluginConfig *PluginConfig } // PluginConfig holds plugin configuration. @@ -241,9 +232,8 @@ type PluginConfig struct { // further categorizing plugins. DirectoryPath string - // GoEnabled is true if goplugins are enabled. - // See https://golang.org/pkg/plugin - GoEnabled bool + // Enabled is true if plugins are enabled. + Enabled bool } // ConfigMapArgs contains the metadata of how to generate a configmap. From 47c965481f64cadd64ccb06ccb27ca5bf7c7c5ac Mon Sep 17 00:00:00 2001 From: jregan Date: Mon, 27 May 2019 08:21:10 -0700 Subject: [PATCH 04/12] Reduce k8ds deps --- examples/zh/README-CN.md | 3 +- internal/loadertest/fakeloader.go | 40 ++-- .../configmapandsecret/configmapfactory.go | 39 ++-- .../configmapfactory_test.go | 3 +- k8sdeps/configmapandsecret/factory.go | 89 +------- k8sdeps/configmapandsecret/factory_test.go | 45 ---- k8sdeps/configmapandsecret/secretfactory.go | 25 +-- .../configmapandsecret/secretfactory_test.go | 3 +- k8sdeps/kv/kv.go | 101 --------- k8sdeps/kv/kv_test.go | 68 ------ k8sdeps/kv/util.go | 65 ------ k8sdeps/transformer/factory.go | 21 +- k8sdeps/transformer/inventory/inventory.go | 6 +- .../transformer/inventory/inventory_test.go | 25 +-- k8sdeps/validator/validators.go | 41 ++-- pkg/commands/build/build.go | 25 +-- pkg/commands/commands.go | 5 +- pkg/commands/edit/add/all.go | 36 ++-- pkg/commands/edit/add/configmap.go | 9 +- pkg/commands/edit/add/configmap_test.go | 6 +- pkg/commands/edit/add/secret.go | 9 +- pkg/commands/edit/add/secret_test.go | 6 +- pkg/commands/edit/all.go | 30 +-- pkg/ifc/ifc.go | 23 +- pkg/ifc/transformer/factory.go | 19 +- pkg/loader/fileloader.go | 106 +++++----- pkg/loader/fileloader_test.go | 28 ++- pkg/loader/kv.go | 200 ++++++++++++++++++ pkg/loader/kv_test.go | 91 ++++++++ pkg/loader/loader.go | 5 +- pkg/plugins/config.go | 2 +- pkg/plugins/loader.go | 2 +- pkg/resmap/factory_test.go | 6 +- pkg/target/kusttarget.go | 2 +- pkg/target/plugindir_test.go | 4 +- pkg/transformers/config/factory_test.go | 39 +--- pkg/types/kustomization.go | 6 + pkg/validators/validators.go | 27 ++- .../SecretsFromDatabase.go | 1 + 39 files changed, 563 insertions(+), 698 deletions(-) delete mode 100644 k8sdeps/configmapandsecret/factory_test.go delete mode 100644 k8sdeps/kv/kv.go delete mode 100644 k8sdeps/kv/kv_test.go delete mode 100644 k8sdeps/kv/util.go create mode 100644 pkg/loader/kv.go create mode 100644 pkg/loader/kv_test.go 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) } From 02f379536c5a5017e1587e75457d42188fbe215e Mon Sep 17 00:00:00 2001 From: jregan Date: Mon, 27 May 2019 17:05:55 -0700 Subject: [PATCH 05/12] Idiom fixes. - func/struct names prefixed with package name - public funcs/structs that should be private --- k8sdeps/transformer/factory.go | 6 +-- .../transformer/hash/{hash.go => kusthash.go} | 42 ++++++----------- .../hash/{hash_test.go => kusthash_test.go} | 4 +- k8sdeps/transformer/hash/namehash.go | 47 ------------------- k8sdeps/transformer/hash/transformer.go | 34 ++++++++++++++ .../{namehash_test.go => transformer_test.go} | 19 ++------ .../{inventory.go => transformer.go} | 26 +++++----- ...{inventory_test.go => transformer_test.go} | 4 +- ...onflictdetector.go => conflictdetector.go} | 17 +------ .../patch/{patch.go => transformer.go} | 43 ++++++----------- .../{patch_test.go => transformer_test.go} | 29 ++++-------- 11 files changed, 97 insertions(+), 174 deletions(-) rename k8sdeps/transformer/hash/{hash.go => kusthash.go} (78%) rename k8sdeps/transformer/hash/{hash_test.go => kusthash_test.go} (99%) delete mode 100644 k8sdeps/transformer/hash/namehash.go create mode 100644 k8sdeps/transformer/hash/transformer.go rename k8sdeps/transformer/hash/{namehash_test.go => transformer_test.go} (85%) rename k8sdeps/transformer/inventory/{inventory.go => transformer.go} (83%) rename k8sdeps/transformer/inventory/{inventory_test.go => transformer_test.go} (97%) rename k8sdeps/transformer/patch/{patchconflictdetector.go => conflictdetector.go} (85%) rename k8sdeps/transformer/patch/{patch.go => transformer.go} (75%) rename k8sdeps/transformer/patch/{patch_test.go => transformer_test.go} (93%) diff --git a/k8sdeps/transformer/factory.go b/k8sdeps/transformer/factory.go index 61dff0ab5..5a6a0b8d3 100644 --- a/k8sdeps/transformer/factory.go +++ b/k8sdeps/transformer/factory.go @@ -26,12 +26,12 @@ func NewFactoryImpl() *FactoryImpl { func (p *FactoryImpl) MakePatchTransformer( slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error) { - return patch.NewPatchTransformer(slice, rf) + return patch.NewTransformer(slice, rf) } // MakeHashTransformer makes a new name hash transformer func (p *FactoryImpl) MakeHashTransformer() transformers.Transformer { - return hash.NewNameHashTransformer() + return hash.NewTransformer() } func (p *FactoryImpl) MakeInventoryTransformer( @@ -39,5 +39,5 @@ func (p *FactoryImpl) MakeInventoryTransformer( ldr ifc.Loader, namespace string, gp types.GarbagePolicy) transformers.Transformer { - return inventory.NewInventoryTransformer(arg, ldr, namespace, gp) + return inventory.NewTransformer(arg, ldr, namespace, gp) } diff --git a/k8sdeps/transformer/hash/hash.go b/k8sdeps/transformer/hash/kusthash.go similarity index 78% rename from k8sdeps/transformer/hash/hash.go rename to k8sdeps/transformer/hash/kusthash.go index cdab7244b..26c647d83 100644 --- a/k8sdeps/transformer/hash/hash.go +++ b/k8sdeps/transformer/hash/kusthash.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 hash @@ -26,16 +13,16 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -// KustHash compute hash for unstructured objects -type KustHash struct{} +// kustHash computes a hash of an unstructured object. +type kustHash struct{} -// NewKustHash returns a KustHash object -func NewKustHash() *KustHash { - return &KustHash{} +// NewKustHash returns a kustHash object +func NewKustHash() *kustHash { + return &kustHash{} } // Hash returns a hash of either a ConfigMap or a Secret -func (h *KustHash) Hash(m map[string]interface{}) (string, error) { +func (h *kustHash) Hash(m map[string]interface{}) (string, error) { u := unstructured.Unstructured{ Object: m, } @@ -46,22 +33,23 @@ func (h *KustHash) Hash(m map[string]interface{}) (string, error) { if err != nil { return "", err } - return ConfigMapHash(cm) + return configMapHash(cm) case "Secret": sec, err := unstructuredToSecret(u) if err != nil { return "", err } - return SecretHash(sec) + return secretHash(sec) default: - return "", fmt.Errorf("type %s is supported for hashing in %v", kind, m) + return "", fmt.Errorf( + "type %s is not supported for hashing in %v", kind, m) } } -// ConfigMapHash returns a hash of the ConfigMap. +// configMapHash returns a hash of the ConfigMap. // The Data, Kind, and Name are taken into account. -func ConfigMapHash(cm *v1.ConfigMap) (string, error) { +func configMapHash(cm *v1.ConfigMap) (string, error) { encoded, err := encodeConfigMap(cm) if err != nil { return "", err @@ -75,7 +63,7 @@ func ConfigMapHash(cm *v1.ConfigMap) (string, error) { // SecretHash returns a hash of the Secret. // The Data, Kind, Name, and Type are taken into account. -func SecretHash(sec *v1.Secret) (string, error) { +func secretHash(sec *v1.Secret) (string, error) { encoded, err := encodeSecret(sec) if err != nil { return "", err diff --git a/k8sdeps/transformer/hash/hash_test.go b/k8sdeps/transformer/hash/kusthash_test.go similarity index 99% rename from k8sdeps/transformer/hash/hash_test.go rename to k8sdeps/transformer/hash/kusthash_test.go index 4a3c9365c..47d783498 100644 --- a/k8sdeps/transformer/hash/hash_test.go +++ b/k8sdeps/transformer/hash/kusthash_test.go @@ -54,7 +54,7 @@ func TestConfigMapHash(t *testing.T) { } for _, c := range cases { - h, err := ConfigMapHash(c.cm) + h, err := configMapHash(c.cm) if SkipRest(t, c.desc, err, c.err) { continue } @@ -80,7 +80,7 @@ func TestSecretHash(t *testing.T) { } for _, c := range cases { - h, err := SecretHash(c.secret) + h, err := secretHash(c.secret) if SkipRest(t, c.desc, err, c.err) { continue } diff --git a/k8sdeps/transformer/hash/namehash.go b/k8sdeps/transformer/hash/namehash.go deleted file mode 100644 index a52072e8a..000000000 --- a/k8sdeps/transformer/hash/namehash.go +++ /dev/null @@ -1,47 +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 hash - -import ( - "fmt" - - "sigs.k8s.io/kustomize/pkg/resmap" - "sigs.k8s.io/kustomize/pkg/transformers" -) - -type nameHashTransformer struct{} - -var _ transformers.Transformer = &nameHashTransformer{} - -// NewNameHashTransformer construct a nameHashTransformer. -func NewNameHashTransformer() transformers.Transformer { - return &nameHashTransformer{} -} - -// Transform appends hash to generated resources. -func (o *nameHashTransformer) Transform(m resmap.ResMap) error { - for _, res := range m { - if res.NeedHashSuffix() { - h, err := NewKustHash().Hash(res.Map()) - if err != nil { - return err - } - res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h)) - } - } - return nil -} diff --git a/k8sdeps/transformer/hash/transformer.go b/k8sdeps/transformer/hash/transformer.go new file mode 100644 index 000000000..3e0e3123a --- /dev/null +++ b/k8sdeps/transformer/hash/transformer.go @@ -0,0 +1,34 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package hash + +import ( + "fmt" + + "sigs.k8s.io/kustomize/pkg/resmap" + "sigs.k8s.io/kustomize/pkg/transformers" +) + +type transformer struct{} + +var _ transformers.Transformer = &transformer{} + +// NewTransformer make a hash transformer. +func NewTransformer() transformers.Transformer { + return &transformer{} +} + +// Transform appends hash to generated resources. +func (tf *transformer) Transform(m resmap.ResMap) error { + for _, res := range m { + if res.NeedHashSuffix() { + h, err := NewKustHash().Hash(res.Map()) + if err != nil { + return err + } + res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h)) + } + } + return nil +} diff --git a/k8sdeps/transformer/hash/namehash_test.go b/k8sdeps/transformer/hash/transformer_test.go similarity index 85% rename from k8sdeps/transformer/hash/namehash_test.go rename to k8sdeps/transformer/hash/transformer_test.go index 7ca724511..cf182671e 100644 --- a/k8sdeps/transformer/hash/namehash_test.go +++ b/k8sdeps/transformer/hash/transformer_test.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 hash @@ -152,7 +139,7 @@ func TestNameHashTransformer(t *testing.T) { }, &types.GeneratorArgs{Behavior: "create"}, &types.GeneratorOptions{DisableNameSuffixHash: false}), } - tran := NewNameHashTransformer() + tran := NewTransformer() tran.Transform(objs) if !reflect.DeepEqual(objs, expected) { diff --git a/k8sdeps/transformer/inventory/inventory.go b/k8sdeps/transformer/inventory/transformer.go similarity index 83% rename from k8sdeps/transformer/inventory/inventory.go rename to k8sdeps/transformer/inventory/transformer.go index 61fe389a6..431c8c280 100644 --- a/k8sdeps/transformer/inventory/inventory.go +++ b/k8sdeps/transformer/inventory/transformer.go @@ -17,18 +17,18 @@ import ( "sigs.k8s.io/kustomize/pkg/types" ) -// inventoryTransformer compute the inventory object used in prune -type inventoryTransformer struct { +// transformer compute the inventory object used in prune +type transformer struct { garbagePolicy types.GarbagePolicy ldr ifc.Loader cmName string cmNamespace string } -var _ transformers.Transformer = &inventoryTransformer{} +var _ transformers.Transformer = &transformer{} -// NewInventoryTransformer makes a inventoryTransformer. -func NewInventoryTransformer( +// NewTransformer makes a new inventory transformer. +func NewTransformer( p *types.Inventory, ldr ifc.Loader, namespace string, @@ -36,7 +36,7 @@ func NewInventoryTransformer( if p == nil || p.Type != "ConfigMap" || p.ConfigMap.Namespace != namespace { return transformers.NewNoOpTransformer() } - return &inventoryTransformer{ + return &transformer{ garbagePolicy: gp, ldr: ldr, cmName: p.ConfigMap.Name, @@ -52,7 +52,7 @@ func NewInventoryTransformer( // The inventory data is written to annotation since // 1. The key in data field is constrained and couldn't include arbitrary letters // 2. The annotation can be put into any kind of objects -func (o *inventoryTransformer) Transform(m resmap.ResMap) error { +func (tf *transformer) Transform(m resmap.ResMap) error { invty := inventory.NewInventory() var keys []string for _, r := range m { @@ -74,8 +74,8 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error { } args := &types.ConfigMapArgs{} - args.Name = o.cmName - args.Namespace = o.cmNamespace + args.Name = tf.cmName + args.Namespace = tf.cmNamespace opts := &types.GeneratorOptions{ Annotations: make(map[string]string), } @@ -86,12 +86,12 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error { } kf := kunstruct.NewKunstructuredFactoryImpl() - k, err := kf.MakeConfigMap(o.ldr, opts, args) + k, err := kf.MakeConfigMap(tf.ldr, opts, args) if err != nil { return err } - if o.garbagePolicy == types.GarbageCollect { + if tf.garbagePolicy == types.GarbageCollect { for k := range m { delete(m, k) } @@ -102,8 +102,8 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error { Version: "v1", Kind: "ConfigMap", }, - o.cmName, - "", o.cmNamespace) + tf.cmName, + "", tf.cmNamespace) if _, ok := m[id]; ok { return fmt.Errorf("id %v is already used, please use a different name in the prune field", id) } diff --git a/k8sdeps/transformer/inventory/inventory_test.go b/k8sdeps/transformer/inventory/transformer_test.go similarity index 97% rename from k8sdeps/transformer/inventory/inventory_test.go rename to k8sdeps/transformer/inventory/transformer_test.go index b2fa210c4..0c503d396 100644 --- a/k8sdeps/transformer/inventory/inventory_test.go +++ b/k8sdeps/transformer/inventory/transformer_test.go @@ -139,7 +139,7 @@ func TestInventoryTransformer(t *testing.T) { objs := makeResMap() // include the original resmap; only return the ConfigMap for pruning - tran := NewInventoryTransformer(p, ldr, "default", types.GarbageCollect) + tran := NewTransformer(p, ldr, "default", types.GarbageCollect) tran.Transform(objs) if !reflect.DeepEqual(objs, expected) { @@ -151,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, ldr, "default", types.GarbageIgnore) + tran = NewTransformer(p, ldr, "default", types.GarbageIgnore) tran.Transform(objs) if !reflect.DeepEqual(objs, expected) { diff --git a/k8sdeps/transformer/patch/patchconflictdetector.go b/k8sdeps/transformer/patch/conflictdetector.go similarity index 85% rename from k8sdeps/transformer/patch/patchconflictdetector.go rename to k8sdeps/transformer/patch/conflictdetector.go index 10353c77f..3d8851505 100644 --- a/k8sdeps/transformer/patch/patchconflictdetector.go +++ b/k8sdeps/transformer/patch/conflictdetector.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 patch diff --git a/k8sdeps/transformer/patch/patch.go b/k8sdeps/transformer/patch/transformer.go similarity index 75% rename from k8sdeps/transformer/patch/patch.go rename to k8sdeps/transformer/patch/transformer.go index 357f3daba..a0dcff6b2 100644 --- a/k8sdeps/transformer/patch/patch.go +++ b/k8sdeps/transformer/patch/transformer.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 patch @@ -31,27 +18,27 @@ import ( "sigs.k8s.io/kustomize/pkg/transformers" ) -// patchTransformer applies patches. -type patchTransformer struct { +// transformer applies strategic merge patches. +type transformer struct { patches []*resource.Resource rf *resource.Factory } -var _ transformers.Transformer = &patchTransformer{} +var _ transformers.Transformer = &transformer{} -// NewPatchTransformer constructs a patchTransformer. -func NewPatchTransformer( +// NewTransformer constructs a strategic merge patch transformer. +func NewTransformer( slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error) { if len(slice) == 0 { return transformers.NewNoOpTransformer(), nil } - return &patchTransformer{patches: slice, rf: rf}, nil + return &transformer{patches: slice, rf: rf}, nil } // Transform apply the patches on top of the base resources. -func (pt *patchTransformer) Transform(baseResourceMap resmap.ResMap) error { +func (tf *transformer) Transform(baseResourceMap resmap.ResMap) error { // Merge and then index the patches by Id. - patches, err := pt.mergePatches() + patches, err := tf.mergePatches() if err != nil { return err } @@ -118,9 +105,9 @@ func (pt *patchTransformer) Transform(baseResourceMap resmap.ResMap) error { // mergePatches merge and index patches by Id. // It errors out if there is conflict between patches. -func (pt *patchTransformer) mergePatches() (resmap.ResMap, error) { +func (tf *transformer) mergePatches() (resmap.ResMap, error) { rc := resmap.ResMap{} - for ix, patch := range pt.patches { + for ix, patch := range tf.patches { id := patch.Id() existing, found := rc[id] if !found { @@ -134,9 +121,9 @@ func (pt *patchTransformer) mergePatches() (resmap.ResMap, error) { } var cd conflictDetector if err != nil { - cd = newJMPConflictDetector(pt.rf) + cd = newJMPConflictDetector(tf.rf) } else { - cd, err = newSMPConflictDetector(versionedObj, pt.rf) + cd, err = newSMPConflictDetector(versionedObj, tf.rf) if err != nil { return nil, err } @@ -147,7 +134,7 @@ func (pt *patchTransformer) mergePatches() (resmap.ResMap, error) { return nil, err } if conflict { - conflictingPatch, err := cd.findConflict(ix, pt.patches) + conflictingPatch, err := cd.findConflict(ix, tf.patches) if err != nil { return nil, err } diff --git a/k8sdeps/transformer/patch/patch_test.go b/k8sdeps/transformer/patch/transformer_test.go similarity index 93% rename from k8sdeps/transformer/patch/patch_test.go rename to k8sdeps/transformer/patch/transformer_test.go index d6955a6ee..a47d2d25d 100644 --- a/k8sdeps/transformer/patch/patch_test.go +++ b/k8sdeps/transformer/patch/transformer_test.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 patch @@ -128,7 +115,7 @@ func TestOverlayRun(t *testing.T) { }, }), } - lt, err := NewPatchTransformer(patch, rf) + lt, err := NewTransformer(patch, rf) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -258,7 +245,7 @@ func TestMultiplePatches(t *testing.T) { }, }), } - lt, err := NewPatchTransformer(patch, rf) + lt, err := NewTransformer(patch, rf) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -344,7 +331,7 @@ func TestMultiplePatchesWithConflict(t *testing.T) { ), } - lt, err := NewPatchTransformer(patch, rf) + lt, err := NewTransformer(patch, rf) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -407,7 +394,7 @@ func TestNoSchemaOverlayRun(t *testing.T) { }), } - lt, err := NewPatchTransformer(patch, rf) + lt, err := NewTransformer(patch, rf) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -491,7 +478,7 @@ func TestNoSchemaMultiplePatches(t *testing.T) { }), } - lt, err := NewPatchTransformer(patch, rf) + lt, err := NewTransformer(patch, rf) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -549,7 +536,7 @@ func TestNoSchemaMultiplePatchesWithConflict(t *testing.T) { }), } - lt, err := NewPatchTransformer(patch, rf) + lt, err := NewTransformer(patch, rf) if err != nil { t.Fatalf("unexpected error: %v", err) } From 68f6b0be6e6ba4bd798e8bb246387f0a35bba097 Mon Sep 17 00:00:00 2001 From: Jian Qiu Date: Tue, 28 May 2019 14:02:32 +0800 Subject: [PATCH 06/12] Add Webhookconfiguration in default name references --- pkg/transformers/config/defaultconfig/namereference.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/transformers/config/defaultconfig/namereference.go b/pkg/transformers/config/defaultconfig/namereference.go index 0a3562a5e..524a914fc 100644 --- a/pkg/transformers/config/defaultconfig/namereference.go +++ b/pkg/transformers/config/defaultconfig/namereference.go @@ -252,6 +252,12 @@ nameReference: - path: spec/service/name kind: APIService group: apiregistration.k8s.io + - path: webhooks/clientConfig/service/name + kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + - path: webhooks/clientConfig/service/name + kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io - kind: Role group: rbac.authorization.k8s.io From e6d1de0d72f1b88202f3bc1d0d03b92d2e11eac3 Mon Sep 17 00:00:00 2001 From: wlezzar Date: Mon, 27 May 2019 21:28:01 +0200 Subject: [PATCH 07/12] fix commonLabels spec for volumeClaimTemplates --- pkg/transformers/config/defaultconfig/commonlabels.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/transformers/config/defaultconfig/commonlabels.go b/pkg/transformers/config/defaultconfig/commonlabels.go index 66943c1ed..a61e7ca01 100644 --- a/pkg/transformers/config/defaultconfig/commonlabels.go +++ b/pkg/transformers/config/defaultconfig/commonlabels.go @@ -111,7 +111,7 @@ commonLabels: kind: StatefulSet - path: spec/volumeClaimTemplates/metadata/labels - create: true + create: false group: apps kind: StatefulSet From bb9b3163ee170ae15e2b155c3aae7f361c0af3be Mon Sep 17 00:00:00 2001 From: Jeff Regan Date: Tue, 28 May 2019 17:06:44 -0700 Subject: [PATCH 08/12] Add script to run cloud build 'locally'. --- build/{build.sh => cloudbuild.sh} | 0 build/cloudbuild.yaml | 17 +------- build/cloudbuild_local.yaml | 30 -------------- build/localbuild.sh | 67 +++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 46 deletions(-) rename build/{build.sh => cloudbuild.sh} (100%) delete mode 100644 build/cloudbuild_local.yaml create mode 100755 build/localbuild.sh diff --git a/build/build.sh b/build/cloudbuild.sh similarity index 100% rename from build/build.sh rename to build/cloudbuild.sh diff --git a/build/cloudbuild.yaml b/build/cloudbuild.yaml index c843ecadb..d2233d75e 100644 --- a/build/cloudbuild.yaml +++ b/build/cloudbuild.yaml @@ -1,23 +1,8 @@ -# 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. - -# TODO(droot): add instructions for running in production. steps: - name: "gcr.io/cloud-builders/git" args: [fetch, --tags, --depth=100] - name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch" - args: ["bash", "build/build.sh"] + args: ["bash", "build/cloudbuild.sh"] secretEnv: ['GITHUB_TOKEN'] secrets: - kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token diff --git a/build/cloudbuild_local.yaml b/build/cloudbuild_local.yaml deleted file mode 100644 index f1eb5bb2c..000000000 --- a/build/cloudbuild_local.yaml +++ /dev/null @@ -1,30 +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. - -# Instructions to run locally: -# Download google container builder: https://github.com/kubernetes-sigs/container-builder-local -# Set you GOOS and GOARCH vars to match your system -# Set OUTPUT to the location to write the directory containing the tar.gz -# $ container-builder-local --config=build/cloudbuild_local.yaml --dryrun=false \ -# --substitutions=_GOOS=$GOOS,_GOARCH=$GOARCH --write-workspace=$OUTPUT . -# Release tar will be in $OUTPUT - -steps: -- name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch" - args: ["bash", "build/build.sh", "--snapshot"] - secretEnv: ['GITHUB_TOKEN'] -secrets: -- kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token - secretEnv: - GITHUB_TOKEN: CiQAyrREbPgXJOeT7M3t+WlxkhXwlMPudixBeiyWTjmLOMLqdK4SUQA0W+xUmDJKAhyfHCcwqSEzUn9OwKC7XAYcmwe0CCKTCbPbDgmioDK24q3LVapndXNvnnHvCjhOJNEr1o+P1DCF+LlzYV2YL8lP09rrKrslPg== diff --git a/build/localbuild.sh b/build/localbuild.sh new file mode 100755 index 000000000..c0f7d770b --- /dev/null +++ b/build/localbuild.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# Usage +# +# ./build/localbuild.sh +# +# The script attempts to use cloudbuild configuration +# to create a release "locally". +# +# At the time of writing, +# +# https://pantheon.corp.google.com/cloud-build/triggers?project=kustomize-199618 +# +# has a trigger such that whenever a git tag is +# applied to the kustomize repo, the cloud builder +# reads the repository-relative file +# +# build/cloudbuild.yaml +# +# Inside this yaml file is a reference to the script +# +# build/cloudbuild.sh +# +# The script you are reading now does something +# analogous via docker tricks. + +set -e +# set -x + +if [ -z ${GOPATH+x} ]; then + echo GOPATH is unset; cannot proceed. + exit 1 +fi + +WORK=$(mktemp -d) + +pushd $GOPATH/src/sigs.k8s.io/kustomize +pwd + +echo "Building in $WORK" + +cat </tmp/localbuild.yaml +steps: +- name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch" + args: ["bash", "build/cloudbuild.sh", "--snapshot"] + secretEnv: ['GITHUB_TOKEN'] +secrets: +- kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token + secretEnv: + GITHUB_TOKEN: CiQAyrREbPgXJOeT7M3t+WlxkhXwlMPudixBeiyWTjmLOMLqdK4SUQA0W+xUmDJKAhyfHCcwqSEzUn9OwKC7XAYcmwe0CCKTCbPbDgmioDK24q3LVapndXNvnnHvCjhOJNEr1o+P1DCF+LlzYV2YL8lP09rrKrslPg== +EOF + +# --substitutions=_GOOS=linux,_GOARCH=amd64 + +config=build/cloudbuild.yaml +config=/tmp/localbuild.yaml + +# See https://cloud.google.com/cloud-build/docs/build-debug-locally +cloud-build-local \ + --config=$config \ + --dryrun=false \ + --write-workspace=$WORK \ + . + +tree $WORK + +popd From a7a2589e81b83d6a02741edd98945aac93089b94 Mon Sep 17 00:00:00 2001 From: Jeffrey Regan Date: Tue, 28 May 2019 18:21:07 -0700 Subject: [PATCH 09/12] Fix yaml in generator examples. --- pkg/target/configmaps_test.go | 48 +++++++++++---------- pkg/target/generatormergeandreplace_test.go | 26 +++++------ pkg/target/multiplepatch_test.go | 12 +++--- pkg/target/namespacedgenerators_test.go | 4 +- pkg/target/variableref_test.go | 4 +- 5 files changed, 48 insertions(+), 46 deletions(-) diff --git a/pkg/target/configmaps_test.go b/pkg/target/configmaps_test.go index 2a7dc7738..edc275e2b 100644 --- a/pkg/target/configmaps_test.go +++ b/pkg/target/configmaps_test.go @@ -31,24 +31,26 @@ namePrefix: blah- configMapGenerator: - name: bob literals: - - fruit=apple - - vegetable=broccoli - env: foo.env + - fruit=apple + - vegetable=broccoli + envs: + - foo.env files: - - passphrase=phrase.dat - - forces.txt + - passphrase=phrase.dat + - forces.txt - name: json literals: - - 'v2=[{"path": "var/druid/segment-cache"}]' + - 'v2=[{"path": "var/druid/segment-cache"}]' secretGenerator: - name: bob literals: - - fruit=apple - - vegetable=broccoli - env: foo.env + - fruit=apple + - vegetable=broccoli + envs: + - foo.env files: - - passphrase=phrase.dat - - forces.txt + - passphrase=phrase.dat + - forces.txt `) th.WriteF("/app/foo.env", ` MOUNTAIN=everest @@ -122,15 +124,15 @@ configMapGenerator: - name: bob behavior: create literals: - - bean=pinto - - star=wolf-rayet + - bean=pinto + - star=wolf-rayet literals: - - fruit=apple - - vegetable=broccoli + - fruit=apple + - vegetable=broccoli files: - - forces.txt + - forces.txt files: - - nobles=nobility.txt + - nobles=nobility.txt `) th.WriteF("/app/forces.txt", ` gravitational @@ -177,7 +179,7 @@ configMapGenerator: - name: com1 behavior: create literals: - - from=base + - from=base `) th.WriteK("/app/base2", ` namePrefix: p2- @@ -185,7 +187,7 @@ configMapGenerator: - name: com2 behavior: create literals: - - from=base + - from=base `) th.WriteK("/app/overlay/o1", ` bases: @@ -194,7 +196,7 @@ configMapGenerator: - name: com1 behavior: merge literals: - - from=overlay + - from=overlay `) th.WriteK("/app/overlay/o2", ` bases: @@ -203,7 +205,7 @@ configMapGenerator: - name: com2 behavior: merge literals: - - from=overlay + - from=overlay `) th.WriteK("/app/overlay", ` bases: @@ -213,8 +215,8 @@ configMapGenerator: - name: com1 behavior: merge literals: - - foo=bar - - baz=qux + - foo=bar + - baz=qux `) m, err := th.MakeKustTarget().MakeCustomizedResMap() if err != nil { diff --git a/pkg/target/generatormergeandreplace_test.go b/pkg/target/generatormergeandreplace_test.go index 0bc66fe55..fa946223c 100644 --- a/pkg/target/generatormergeandreplace_test.go +++ b/pkg/target/generatormergeandreplace_test.go @@ -178,14 +178,14 @@ resources: - deployment.yaml - service.yaml configMapGenerator: - - name: configmap-in-base - literals: - - foo=bar +- name: configmap-in-base + literals: + - foo=bar secretGenerator: - name: secret-in-base literals: - - username=admin - - password=somepw + - username=admin + - password=somepw `) th.WriteF("/app/deployment.yaml", ` apiVersion: apps/v1beta2 @@ -354,18 +354,18 @@ patchesStrategicMerge: bases: - ../app configMapGenerator: - - name: configmap-in-overlay - literals: - - hello=world - - name: configmap-in-base - behavior: replace - literals: - - foo=override-bar +- name: configmap-in-overlay + literals: + - hello=world +- name: configmap-in-base + behavior: replace + literals: + - foo=override-bar secretGenerator: - name: secret-in-base behavior: merge literals: - - proxy=haproxy + - proxy=haproxy `) m, err := th.MakeKustTarget().MakeCustomizedResMap() if err != nil { diff --git a/pkg/target/multiplepatch_test.go b/pkg/target/multiplepatch_test.go index 7d75e7eb8..5fce30b1f 100644 --- a/pkg/target/multiplepatch_test.go +++ b/pkg/target/multiplepatch_test.go @@ -38,9 +38,9 @@ resources: - deployment.yaml - service.yaml configMapGenerator: - - name: configmap-in-base - literals: - - foo=bar +- name: configmap-in-base + literals: + - foo=bar `) th.WriteF("/app/base/deployment.yaml", ` apiVersion: apps/v1beta2 @@ -93,9 +93,9 @@ patchesStrategicMerge: bases: - ../../base configMapGenerator: - - name: configmap-in-overlay - literals: - - hello=world +- name: configmap-in-overlay + literals: + - hello=world `) } diff --git a/pkg/target/namespacedgenerators_test.go b/pkg/target/namespacedgenerators_test.go index 3d598ab4e..f62325f44 100644 --- a/pkg/target/namespacedgenerators_test.go +++ b/pkg/target/namespacedgenerators_test.go @@ -42,10 +42,10 @@ secretGenerator: - name: the-non-default-namespace-secret namespace: non-default literals: - - password.txt=verySecret + - password.txt=verySecret - name: the-secret literals: - - password.txt=anotherSecret + - password.txt=anotherSecret `) m, err := th.MakeKustTarget().MakeCustomizedResMap() if err != nil { diff --git a/pkg/target/variableref_test.go b/pkg/target/variableref_test.go index b664e860c..74b647110 100644 --- a/pkg/target/variableref_test.go +++ b/pkg/target/variableref_test.go @@ -32,8 +32,8 @@ resources: configMapGenerator: - name: test-config-map literals: - - foo=bar - - baz=qux + - foo=bar + - baz=qux vars: - name: CDB_PUBLIC_SVC objref: From ca478016c93d5bd1b1db2cbddedc3ce52036e5a9 Mon Sep 17 00:00:00 2001 From: Jeffrey Regan Date: Tue, 28 May 2019 18:32:23 -0700 Subject: [PATCH 10/12] Update minecraft version in example. --- pkg/target/chartinflatorplugin_test.go | 6 +++--- plugin/someteam.example.com/v1/chartinflator/ChartInflator | 4 ++++ .../v1/chartinflator/ChartInflator_test.go | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/target/chartinflatorplugin_test.go b/pkg/target/chartinflatorplugin_test.go index 4112cfac7..580eefd08 100644 --- a/pkg/target/chartinflatorplugin_test.go +++ b/pkg/target/chartinflatorplugin_test.go @@ -61,7 +61,7 @@ kind: Secret metadata: labels: app: release-name-minecraft - chart: minecraft-1.0.0 + chart: minecraft-1.0.1 heritage: Tiller release: release-name name: LOOOOOOOONG-release-name-minecraft @@ -72,7 +72,7 @@ kind: Service metadata: labels: app: release-name-minecraft - chart: minecraft-1.0.0 + chart: minecraft-1.0.1 heritage: Tiller release: release-name name: LOOOOOOOONG-release-name-minecraft @@ -93,7 +93,7 @@ metadata: volume.alpha.kubernetes.io/storage-class: default labels: app: release-name-minecraft - chart: minecraft-1.0.0 + chart: minecraft-1.0.1 heritage: Tiller release: release-name name: LOOOOOOOONG-release-name-minecraft-datadir diff --git a/plugin/someteam.example.com/v1/chartinflator/ChartInflator b/plugin/someteam.example.com/v1/chartinflator/ChartInflator index 127b371b2..fde9032d4 100755 --- a/plugin/someteam.example.com/v1/chartinflator/ChartInflator +++ b/plugin/someteam.example.com/v1/chartinflator/ChartInflator @@ -24,6 +24,10 @@ # Example execution: # ./plugin/someteam.example.com/v1/ChartInflator configFile.yaml +# TODO: allow specification of a specific chart VERSION +# so this test doesn't break every time minecraft is upgraded :P +# See https://github.com/helm/helm/issues/4008 + set -e # Yaml parsing is a ridiculous thing to do in bash, diff --git a/plugin/someteam.example.com/v1/chartinflator/ChartInflator_test.go b/plugin/someteam.example.com/v1/chartinflator/ChartInflator_test.go index 0fca6b53d..8765cbcb8 100644 --- a/plugin/someteam.example.com/v1/chartinflator/ChartInflator_test.go +++ b/plugin/someteam.example.com/v1/chartinflator/ChartInflator_test.go @@ -42,7 +42,7 @@ kind: Secret metadata: labels: app: release-name-minecraft - chart: minecraft-1.0.0 + chart: minecraft-1.0.1 heritage: Tiller release: release-name name: release-name-minecraft @@ -53,7 +53,7 @@ kind: Service metadata: labels: app: release-name-minecraft - chart: minecraft-1.0.0 + chart: minecraft-1.0.1 heritage: Tiller release: release-name name: release-name-minecraft @@ -74,7 +74,7 @@ metadata: volume.alpha.kubernetes.io/storage-class: default labels: app: release-name-minecraft - chart: minecraft-1.0.0 + chart: minecraft-1.0.1 heritage: Tiller release: release-name name: release-name-minecraft-datadir From ee728d58f536c48fbc2d10303a6bfa72dbc6d170 Mon Sep 17 00:00:00 2001 From: jregan Date: Tue, 28 May 2019 21:40:07 -0700 Subject: [PATCH 11/12] Move hashing code out of k8sdeps. --- k8sdeps/transformer/hash/kusthash.go | 57 ++------------------ k8sdeps/transformer/hash/kusthash_test.go | 48 +---------------- k8sdeps/transformer/inventory/transformer.go | 5 +- pkg/hasher/hasher.go | 52 ++++++++++++++++++ pkg/hasher/hasher_test.go | 41 ++++++++++++++ 5 files changed, 101 insertions(+), 102 deletions(-) create mode 100644 pkg/hasher/hasher.go create mode 100644 pkg/hasher/hasher_test.go diff --git a/k8sdeps/transformer/hash/kusthash.go b/k8sdeps/transformer/hash/kusthash.go index 26c647d83..c755698d6 100644 --- a/k8sdeps/transformer/hash/kusthash.go +++ b/k8sdeps/transformer/hash/kusthash.go @@ -4,13 +4,12 @@ package hash import ( - "crypto/sha256" "encoding/json" "fmt" - "sort" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/kustomize/pkg/hasher" ) // kustHash computes a hash of an unstructured object. @@ -54,7 +53,7 @@ func configMapHash(cm *v1.ConfigMap) (string, error) { if err != nil { return "", err } - h, err := encodeHash(hash(encoded)) + h, err := hasher.Encode(hasher.Hash(encoded)) if err != nil { return "", err } @@ -68,22 +67,7 @@ func secretHash(sec *v1.Secret) (string, error) { if err != nil { return "", err } - h, err := encodeHash(hash(encoded)) - if err != nil { - return "", err - } - return h, nil -} - -// SortArrayAndComputeHash sorts a string array and -// returns a hash for it -func SortArrayAndComputeHash(s []string) (string, error) { - sort.Strings(s) - data, err := json.Marshal(s) - if err != nil { - return "", err - } - h, err := encodeHash(hash(string(data))) + h, err := hasher.Encode(hasher.Hash(encoded)) if err != nil { return "", err } @@ -116,41 +100,6 @@ func encodeSecret(sec *v1.Secret) (string, error) { return string(data), nil } -// encodeHash extracts the first 40 bits of the hash from the hex string -// (1 hex char represents 4 bits), and then maps vowels and vowel-like hex -// characters to consonants to prevent bad words from being formed (the theory -// is that no vowels makes it really hard to make bad words). Since the string -// is hex, the only vowels it can contain are 'a' and 'e'. -// We picked some arbitrary consonants to map to from the same character set as GenerateName. -// See: https://github.com/kubernetes/apimachinery/blob/dc1f89aff9a7509782bde3b68824c8043a3e58cc/pkg/util/rand/rand.go#L75 -// If the hex string contains fewer than ten characters, returns an error. -func encodeHash(hex string) (string, error) { - if len(hex) < 10 { - return "", fmt.Errorf("the hex string must contain at least 10 characters") - } - enc := []rune(hex[:10]) - for i := range enc { - switch enc[i] { - case '0': - enc[i] = 'g' - case '1': - enc[i] = 'h' - case '3': - enc[i] = 'k' - case 'a': - enc[i] = 'm' - case 'e': - enc[i] = 't' - } - } - return string(enc), nil -} - -// hash hashes `data` with sha256 and returns the hex string -func hash(data string) string { - return fmt.Sprintf("%x", sha256.Sum256([]byte(data))) -} - func unstructuredToConfigmap(u unstructured.Unstructured) (*v1.ConfigMap, error) { marshaled, err := json.Marshal(u.Object) if err != nil { diff --git a/k8sdeps/transformer/hash/kusthash_test.go b/k8sdeps/transformer/hash/kusthash_test.go index 47d783498..006de9f8d 100644 --- a/k8sdeps/transformer/hash/kusthash_test.go +++ b/k8sdeps/transformer/hash/kusthash_test.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 hash @@ -90,28 +77,6 @@ func TestSecretHash(t *testing.T) { } } -func TestArrayHash(t *testing.T) { - array1 := []string{"a", "b", "c"} - array2 := []string{"c", "b", "a"} - h1, err := SortArrayAndComputeHash(array1) - if err != nil { - t.Errorf("unexpected error %v", err) - } - if h1 == "" { - t.Errorf("failed to hash %v", array1) - } - h2, err := SortArrayAndComputeHash(array2) - if err != nil { - t.Errorf("unexpected error %v", err) - } - if h2 == "" { - t.Errorf("failed to hash %v", array2) - } - if h1 != h2 { - t.Errorf("hash is not consistent with reordered list: %s %s", h1, h2) - } -} - func TestEncodeConfigMap(t *testing.T) { cases := []struct { desc string @@ -178,15 +143,6 @@ func TestEncodeSecret(t *testing.T) { } } -func TestHash(t *testing.T) { - // hash the empty string to be sure that sha256 is being used - expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - sum := hash("") - if expect != sum { - t.Errorf("expected hash %q but got %q", expect, sum) - } -} - // warn devs who change types that they might have to update a hash function // not perfect, as it only checks the number of top-level fields func TestTypeStability(t *testing.T) { diff --git a/k8sdeps/transformer/inventory/transformer.go b/k8sdeps/transformer/inventory/transformer.go index 431c8c280..5b3009831 100644 --- a/k8sdeps/transformer/inventory/transformer.go +++ b/k8sdeps/transformer/inventory/transformer.go @@ -5,9 +5,10 @@ package inventory import ( "fmt" + "sigs.k8s.io/kustomize/k8sdeps/kunstruct" - "sigs.k8s.io/kustomize/k8sdeps/transformer/hash" "sigs.k8s.io/kustomize/pkg/gvk" + "sigs.k8s.io/kustomize/pkg/hasher" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/inventory" "sigs.k8s.io/kustomize/pkg/resid" @@ -68,7 +69,7 @@ func (tf *transformer) Transform(m resmap.ResMap) error { invty.Current[item] = refs keys = append(keys, item.String()) } - h, err := hash.SortArrayAndComputeHash(keys) + h, err := hasher.SortArrayAndComputeHash(keys) if err != nil { return err } diff --git a/pkg/hasher/hasher.go b/pkg/hasher/hasher.go new file mode 100644 index 000000000..77ded7fdf --- /dev/null +++ b/pkg/hasher/hasher.go @@ -0,0 +1,52 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package hasher + +import ( + "crypto/sha256" + "encoding/json" + "fmt" + "sort" +) + +// SortArrayAndComputeHash sorts a string array and +// returns a hash for it +func SortArrayAndComputeHash(s []string) (string, error) { + sort.Strings(s) + data, err := json.Marshal(s) + if err != nil { + return "", err + } + return Encode(Hash(string(data))) +} + +// Copied from https://github.com/kubernetes/kubernetes +// /blob/master/pkg/kubectl/util/hash/hash.go +func Encode(hex string) (string, error) { + if len(hex) < 10 { + return "", fmt.Errorf( + "input length must be at least 10.") + } + enc := []rune(hex[:10]) + for i := range enc { + switch enc[i] { + case '0': + enc[i] = 'g' + case '1': + enc[i] = 'h' + case '3': + enc[i] = 'k' + case 'a': + enc[i] = 'm' + case 'e': + enc[i] = 't' + } + } + return string(enc), nil +} + +// Hash returns the hex form of the sha256 of the argument. +func Hash(data string) string { + return fmt.Sprintf("%x", sha256.Sum256([]byte(data))) +} diff --git a/pkg/hasher/hasher_test.go b/pkg/hasher/hasher_test.go new file mode 100644 index 000000000..970fb4968 --- /dev/null +++ b/pkg/hasher/hasher_test.go @@ -0,0 +1,41 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package hasher_test + +import ( + "testing" + + . "sigs.k8s.io/kustomize/pkg/hasher" +) + +func TestSortArrayAndComputeHash(t *testing.T) { + array1 := []string{"a", "b", "c", "d"} + array2 := []string{"c", "b", "d", "a"} + h1, err := SortArrayAndComputeHash(array1) + if err != nil { + t.Errorf("unexpected error %v", err) + } + if h1 == "" { + t.Errorf("failed to hash %v", array1) + } + h2, err := SortArrayAndComputeHash(array2) + if err != nil { + t.Errorf("unexpected error %v", err) + } + if h2 == "" { + t.Errorf("failed to hash %v", array2) + } + if h1 != h2 { + t.Errorf("hash is not consistent with reordered list: %s %s", h1, h2) + } +} + +func TestHash(t *testing.T) { + // hash the empty string to be sure that sha256 is being used + expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + sum := Hash("") + if expect != sum { + t.Errorf("expected hash %q but got %q", expect, sum) + } +} From a2e4f6cf68a4b097a3ff766514c36ae48ab0050d Mon Sep 17 00:00:00 2001 From: jregan Date: Tue, 28 May 2019 21:56:22 -0700 Subject: [PATCH 12/12] Rename ./bin dir to ./travis. --- .travis.yml | 4 ++-- {bin => travis}/consider-early-travis-exit.sh | 0 {bin => travis}/pre-commit.sh | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename {bin => travis}/consider-early-travis-exit.sh (100%) rename {bin => travis}/pre-commit.sh (100%) diff --git a/.travis.yml b/.travis.yml index 6867c1279..656650745 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ env: - GOLANGCI_RELEASE="v1.12" before_install: - - source ./bin/consider-early-travis-exit.sh + - source ./travis/consider-early-travis-exit.sh - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $GOPATH/bin ${GOLANGCI_RELEASE} - go get -u github.com/monopole/mdrip # The following would install Helm if needed for some reason. @@ -39,7 +39,7 @@ before_install: install: true script: - - ./bin/pre-commit.sh + - ./travis/pre-commit.sh # TBD. Suppressing for now. notifications: diff --git a/bin/consider-early-travis-exit.sh b/travis/consider-early-travis-exit.sh similarity index 100% rename from bin/consider-early-travis-exit.sh rename to travis/consider-early-travis-exit.sh diff --git a/bin/pre-commit.sh b/travis/pre-commit.sh similarity index 100% rename from bin/pre-commit.sh rename to travis/pre-commit.sh