Merge remote-tracking branch 'upstream/master'

This commit is contained in:
郭旭东
2019-05-29 14:08:40 +08:00
88 changed files with 1322 additions and 2265 deletions

View File

@@ -27,7 +27,7 @@ env:
- GOLANGCI_RELEASE="v1.12" - GOLANGCI_RELEASE="v1.12"
before_install: 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} - 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 - go get -u github.com/monopole/mdrip
# The following would install Helm if needed for some reason. # The following would install Helm if needed for some reason.
@@ -39,7 +39,7 @@ before_install:
install: true install: true
script: script:
- ./bin/pre-commit.sh - ./travis/pre-commit.sh
# TBD. Suppressing for now. # TBD. Suppressing for now.
notifications: notifications:

View File

@@ -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: steps:
- name: "gcr.io/cloud-builders/git" - name: "gcr.io/cloud-builders/git"
args: [fetch, --tags, --depth=100] args: [fetch, --tags, --depth=100]
- name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch" - name: "gcr.io/kustomize-199618/golang_with_goreleaser:1.10-stretch"
args: ["bash", "build/build.sh"] args: ["bash", "build/cloudbuild.sh"]
secretEnv: ['GITHUB_TOKEN'] secretEnv: ['GITHUB_TOKEN']
secrets: secrets:
- kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token - kmsKeyName: projects/kustomize-199618/locations/global/keyRings/github-tokens/cryptoKeys/gh-release-token

View File

@@ -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==

67
build/localbuild.sh Executable file
View File

@@ -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 <<EOF >/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

View File

@@ -173,13 +173,10 @@ transformers cannot be expected to be commutative.
A `kustomize build` that tries to use plugins but A `kustomize build` that tries to use plugins but
omits the flag omits the flag
_TODO: Change flag_ > `--enable_alpha_plugins`
> `--enable_alpha_goplugins_accept_panic_risk`
will fail with a warning about plugin use. will fail with a warning about plugin use.
Flag use is an opt-in acknowledging the absence of Flag use is an opt-in acknowledging the absence of
plugin provenance. It's meant to give pause to plugin provenance. It's meant to give pause to
someone who blindly downloads a kustomization from someone who blindly downloads a kustomization from

View File

@@ -12,46 +12,57 @@ tests, and should work with HEAD
go get sigs.k8s.io/kustomize go get sigs.k8s.io/kustomize
``` ```
* [hello world](helloWorld/README.md) - Deploy multiple Basic Usage
(differently configured) variants of a simple Hello
World server.
* [last mile helm](chart.md) - Make last mile modifications to * [configGenerations](configGeneration.md) -
a helm chart. Rolling update when ConfigMapGenerator changes.
* [LDAP](ldap/README.md) - Deploy multiple * [combineConfigs](combineConfigs.md) -
(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) -
Mixing configuration data from different owners Mixing configuration data from different owners
(e.g. devops/SRE and developers). (e.g. devops/SRE and developers).
* [generatorOptions](generatorOptions.md) -
Modifying behavior of all ConfigMap and Secret generators.
* [configGenerations](configGeneration.md) - * [vars](wordpress/README.md) - Injecting k8s runtime data into
Rolling update when ConfigMapGenerator changes. 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) - Multi Variant Examples
Modifying behavior of all ConfigMap and Secret generators.
* [breakfast](breakfast.md) - Customize breakfast for * [hello world](helloWorld/README.md) - Deploy multiple
Alice and Bob. (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 * [mySql](mySql/README.md) - Create a MySQL production
container arguments (e.g. to point wordpress to a SQL service) by vars. configuration from scratch.
* [image names and tags](image.md) - Updating image names and tags without applying a patch. * [breakfast](breakfast.md) - Customize breakfast for
Alice and Bob.
* [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base.
* [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

View File

@@ -150,8 +150,7 @@ correct environment and flags for plugins:
``` ```
function kustomizeIt { function kustomizeIt {
XDG_CONFIG_HOME=$DEMO_HOME \ XDG_CONFIG_HOME=$DEMO_HOME \
kustomize build \ kustomize build --enable_alpha_plugins \
--enable_alpha_goplugins_accept_panic_risk \
$DEMO_HOME/$1 $DEMO_HOME/$1
} }
``` ```

View File

@@ -201,9 +201,7 @@ can be found under `$DEMO_HOME`:
``` ```
result=$( \ result=$( \
XDG_CONFIG_HOME=$DEMO_HOME \ XDG_CONFIG_HOME=$DEMO_HOME \
kustomize \ kustomize build --enable_alpha_plugins $DEMO_HOME )
--enable_alpha_goplugins_accept_panic_risk \
build $DEMO_HOME )
echo "$result" echo "$result"
# Spot check the result: # Spot check the result:
test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=") test 1 == $(echo "$result" | grep -c "FRUIT: YXBwbGU=")

View File

@@ -165,4 +165,14 @@ In addition to the default transformers, you can create custom transformer confi
- [support a CRD type](crd/README.md) - [support a CRD type](crd/README.md)
- add extra fields for variable substitution - add extra fields for variable substitution
- add extra fields for name reference - 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`

View File

@@ -6,7 +6,6 @@
这些示例通过了 [pre-commit](../../bin/pre-commit.sh) 测试,并且应该与 HEAD 一起使用。 这些示例通过了 [pre-commit](../../bin/pre-commit.sh) 测试,并且应该与 HEAD 一起使用。
<!-- @installkustomize @test -->
``` ```
go get sigs.k8s.io/kustomize go get sigs.k8s.io/kustomize
``` ```
@@ -26,7 +25,7 @@ go get sigs.k8s.io/kustomize
* [configGenerations](../configGeneration.md) - 当 ConfigMapGenerator 修改时进行滚动更新。 * [configGenerations](../configGeneration.md) - 当 ConfigMapGenerator 修改时进行滚动更新。
* [secret generation](../kvSourceGoPlugin.md) - 生成 Secret。 * [secret generation](../secretGeneratorPlugin.md) - 生成 Secret。
* [generatorOptions](../generatorOptions.md) -修改所有 ConfigMapGenerator 和 SecretGenerator 的行为。 * [generatorOptions](../generatorOptions.md) -修改所有 ConfigMapGenerator 和 SecretGenerator 的行为。

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 loadertest holds a fake for the Loader interface. // Package loadertest holds a fake for the Loader interface.
package loadertest package loadertest
@@ -22,6 +9,8 @@ import (
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/loader" "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. // 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. // Create fake filesystem and inject it into initial Loader.
fSys := fs.MakeFakeFS() fSys := fs.MakeFakeFS()
fSys.Mkdir(initialDir) fSys.Mkdir(initialDir)
ldr, err := loader.NewLoader(lr, initialDir, fSys) ldr, err := loader.NewLoader(
lr, validators.MakeFakeValidator(), initialDir, fSys)
if err != nil { if err != nil {
log.Fatalf("Unable to make loader: %v", err) log.Fatalf("Unable to make loader: %v", err)
} }
@@ -63,7 +53,7 @@ func (f FakeLoader) AddDirectory(fullDirPath string) error {
return f.fs.Mkdir(fullDirPath) return f.fs.Mkdir(fullDirPath)
} }
// Root returns root. // Root delegates.
func (f FakeLoader) Root() string { func (f FakeLoader) Root() string {
return f.delegate.Root() 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 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) { func (f FakeLoader) Load(location string) ([]byte, error) {
return f.delegate.Load(location) return f.delegate.Load(location)
} }
// Cleanup does nothing // Cleanup delegates.
func (f FakeLoader) Cleanup() error { 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)
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 configmapandsecret generates configmaps and secrets per generator rules. // Package configmapandsecret generates configmaps and secrets per generator rules.
package configmapandsecret package configmapandsecret
@@ -39,13 +26,13 @@ func makeFreshConfigMap(
// MakeConfigMap returns a new ConfigMap, or nil and an error. // MakeConfigMap returns a new ConfigMap, or nil and an error.
func (f *Factory) MakeConfigMap( func (f *Factory) MakeConfigMap(
args *types.ConfigMapArgs) (*v1.ConfigMap, error) { args *types.ConfigMapArgs) (*v1.ConfigMap, error) {
all, err := f.loadKvPairs(args.GeneratorArgs) all, err := f.ldr.LoadKvPairs(args.GeneratorArgs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
cm := makeFreshConfigMap(args) cm := makeFreshConfigMap(args)
for _, p := range all { for _, p := range all {
err = addKvToConfigMap(cm, p.Key, p.Value) err = f.addKvToConfigMap(cm, p)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -59,26 +46,26 @@ func (f *Factory) MakeConfigMap(
// addKvToConfigMap adds the given key and data to the given config map. // addKvToConfigMap adds the given key and data to the given config map.
// Error if key invalid, or already exists. // Error if key invalid, or already exists.
func addKvToConfigMap(configMap *v1.ConfigMap, keyName, data string) error { func (f *Factory) addKvToConfigMap(configMap *v1.ConfigMap, p types.Pair) error {
if err := errIfInvalidKey(keyName); err != nil { if err := f.ldr.Validator().ErrIfInvalidKey(p.Key); err != nil {
return err return err
} }
// If the configmap data contains byte sequences that are all in the UTF-8 // If the configmap data contains byte sequences that are all in the UTF-8
// range, we will write it to .Data // range, we will write it to .Data
if utf8.Valid([]byte(data)) { if utf8.Valid([]byte(p.Value)) {
if _, entryExists := configMap.Data[keyName]; entryExists { if _, entryExists := configMap.Data[p.Key]; entryExists {
return fmt.Errorf(keyExistsErrorMsg, keyName, configMap.Data) return fmt.Errorf(keyExistsErrorMsg, p.Key, configMap.Data)
} }
configMap.Data[keyName] = data configMap.Data[p.Key] = p.Value
return nil return nil
} }
// otherwise, it's BinaryData // otherwise, it's BinaryData
if configMap.BinaryData == nil { if configMap.BinaryData == nil {
configMap.BinaryData = map[string][]byte{} configMap.BinaryData = map[string][]byte{}
} }
if _, entryExists := configMap.BinaryData[keyName]; entryExists { if _, entryExists := configMap.BinaryData[p.Key]; entryExists {
return fmt.Errorf(keyExistsErrorMsg, keyName, configMap.BinaryData) return fmt.Errorf(keyExistsErrorMsg, p.Key, configMap.BinaryData)
} }
configMap.BinaryData[keyName] = []byte(data) configMap.BinaryData[p.Key] = []byte(p.Value)
return nil return nil
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 configmapandsecret package configmapandsecret
@@ -22,10 +9,10 @@ import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/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/fs"
"sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
"sigs.k8s.io/kustomize/pkg/validators"
) )
func makeEnvConfigMap(name string) *corev1.ConfigMap { func makeEnvConfigMap(name string) *corev1.ConfigMap {
@@ -142,10 +129,9 @@ func TestConstructConfigMap(t *testing.T) {
fSys.WriteFile("/configmap/app.env", []byte("DB_USERNAME=admin\nDB_PASSWORD=somepw\n")) 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-init.ini", []byte("FOO=bar\nBAR=baz\n"))
fSys.WriteFile("/configmap/app.bin", []byte{0xff, 0xfd}) fSys.WriteFile("/configmap/app.bin", []byte{0xff, 0xfd})
ldr := loader.NewFileLoaderAtRoot(fSys) ldr := loader.NewFileLoaderAtRoot(validators.MakeFakeValidator(), fSys)
reg := plugin.NewRegistry(ldr)
for _, tc := range testCases { for _, tc := range testCases {
f := NewFactory(ldr, tc.options, reg) f := NewFactory(ldr, tc.options)
cm, err := f.MakeConfigMap(&tc.input) cm, err := f.MakeConfigMap(&tc.input)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)

View File

@@ -1,30 +1,9 @@
/* // Copyright 2019 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 configmapandsecret package configmapandsecret
import ( 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/ifc"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
) )
@@ -33,126 +12,12 @@ import (
type Factory struct { type Factory struct {
ldr ifc.Loader ldr ifc.Loader
options *types.GeneratorOptions options *types.GeneratorOptions
reg plugin.Registry
} }
// NewFactory returns a new Factory. // NewFactory returns a new factory that makes ConfigMaps and Secrets.
func NewFactory( func NewFactory(
l ifc.Loader, o *types.GeneratorOptions, reg plugin.Registry) *Factory { ldr ifc.Loader, o *types.GeneratorOptions) *Factory {
return &Factory{ldr: l, options: o, reg: reg} return &Factory{ldr: ldr, 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)
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
} }
const keyExistsErrorMsg = "cannot add key %s, another key by that name already exists: %v" 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) 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 {
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
}

View File

@@ -1,139 +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 configmapandsecret
import (
"reflect"
"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) {
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"))
ldr := loader.NewFileLoaderAtRoot(fSys)
reg := plugin.NewRegistry(ldr)
bf := NewFactory(loader.NewFileLoaderAtRoot(fSys), nil, reg)
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)
}
}
}
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)
}
}
}

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 configmapandsecret package configmapandsecret
@@ -41,13 +28,13 @@ func makeFreshSecret(
// MakeSecret returns a new secret. // MakeSecret returns a new secret.
func (f *Factory) MakeSecret( func (f *Factory) MakeSecret(
args *types.SecretArgs) (*corev1.Secret, error) { args *types.SecretArgs) (*corev1.Secret, error) {
all, err := f.loadKvPairs(args.GeneratorArgs) all, err := f.ldr.LoadKvPairs(args.GeneratorArgs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s := makeFreshSecret(args) s := makeFreshSecret(args)
for _, p := range all { for _, p := range all {
err = addKvToSecret(s, p.Key, p.Value) err = f.addKvToSecret(s, p.Key, p.Value)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -59,8 +46,8 @@ func (f *Factory) MakeSecret(
return s, nil return s, nil
} }
func addKvToSecret(secret *corev1.Secret, keyName, data string) error { func (f *Factory) addKvToSecret(secret *corev1.Secret, keyName, data string) error {
if err := errIfInvalidKey(keyName); err != nil { if err := f.ldr.Validator().ErrIfInvalidKey(keyName); err != nil {
return err return err
} }
if _, entryExists := secret.Data[keyName]; entryExists { if _, entryExists := secret.Data[keyName]; entryExists {

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 configmapandsecret package configmapandsecret
@@ -22,10 +9,10 @@ import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/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/fs"
"sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
"sigs.k8s.io/kustomize/pkg/validators"
) )
func makeEnvSecret(name string) *corev1.Secret { func makeEnvSecret(name string) *corev1.Secret {
@@ -139,10 +126,9 @@ func TestConstructSecret(t *testing.T) {
fSys := fs.MakeFakeFS() fSys := fs.MakeFakeFS()
fSys.WriteFile("/secret/app.env", []byte("DB_USERNAME=admin\nDB_PASSWORD=somepw\n")) 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")) fSys.WriteFile("/secret/app-init.ini", []byte("FOO=bar\nBAR=baz\n"))
ldr := loader.NewFileLoaderAtRoot(fSys) ldr := loader.NewFileLoaderAtRoot(validators.MakeFakeValidator(), fSys)
reg := plugin.NewRegistry(ldr)
for _, tc := range testCases { for _, tc := range testCases {
f := NewFactory(ldr, tc.options, reg) f := NewFactory(ldr, tc.options)
cm, err := f.MakeSecret(&tc.input) cm, err := f.MakeSecret(&tc.input)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 kunstruct package kunstruct
@@ -25,28 +12,19 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/yaml" "k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/kustomize/k8sdeps/configmapandsecret" "sigs.k8s.io/kustomize/k8sdeps/configmapandsecret"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
) )
// KunstructuredFactoryImpl hides construction using apimachinery types. // KunstructuredFactoryImpl hides construction using apimachinery types.
type KunstructuredFactoryImpl struct { type KunstructuredFactoryImpl struct {
generatorMetaArgs *types.GeneratorMetaArgs
} }
var _ ifc.KunstructuredFactory = &KunstructuredFactoryImpl{} var _ ifc.KunstructuredFactory = &KunstructuredFactoryImpl{}
// NewKunstructuredFactoryImpl returns a factory. // NewKunstructuredFactoryImpl returns a factory.
func NewKunstructuredFactoryImpl() ifc.KunstructuredFactory { func NewKunstructuredFactoryImpl() ifc.KunstructuredFactory {
return NewKunstructuredFactoryWithGeneratorArgs( return &KunstructuredFactoryImpl{}
&types.GeneratorMetaArgs{})
}
// NewKunstructuredFactoryWithGeneratorArgs returns a factory.
func NewKunstructuredFactoryWithGeneratorArgs(
gma *types.GeneratorMetaArgs) ifc.KunstructuredFactory {
return &KunstructuredFactoryImpl{gma}
} }
// SliceFromBytes returns a slice of Kunstructured. // SliceFromBytes returns a slice of Kunstructured.
@@ -91,9 +69,7 @@ func (kf *KunstructuredFactoryImpl) MakeConfigMap(
options *types.GeneratorOptions, options *types.GeneratorOptions,
args *types.ConfigMapArgs) (ifc.Kunstructured, error) { args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory( o, err := configmapandsecret.NewFactory(
ldr, options, ldr, options).MakeConfigMap(args)
plugin.NewConfiguredRegistry(
ldr, kf.generatorMetaArgs.PluginConfig)).MakeConfigMap(args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -106,9 +82,7 @@ func (kf *KunstructuredFactoryImpl) MakeSecret(
options *types.GeneratorOptions, options *types.GeneratorOptions,
args *types.SecretArgs) (ifc.Kunstructured, error) { args *types.SecretArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory( o, err := configmapandsecret.NewFactory(
ldr, options, ldr, options).MakeSecret(args)
plugin.NewConfiguredRegistry(
ldr, kf.generatorMetaArgs.PluginConfig)).MakeSecret(args)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -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
}

View File

@@ -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)
}
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 transformer provides transformer factory // Package transformer provides transformer factory
package transformer package transformer
@@ -21,6 +8,7 @@ import (
"sigs.k8s.io/kustomize/k8sdeps/transformer/hash" "sigs.k8s.io/kustomize/k8sdeps/transformer/hash"
"sigs.k8s.io/kustomize/k8sdeps/transformer/inventory" "sigs.k8s.io/kustomize/k8sdeps/transformer/inventory"
"sigs.k8s.io/kustomize/k8sdeps/transformer/patch" "sigs.k8s.io/kustomize/k8sdeps/transformer/patch"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/transformers" "sigs.k8s.io/kustomize/pkg/transformers"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
@@ -38,17 +26,18 @@ func NewFactoryImpl() *FactoryImpl {
func (p *FactoryImpl) MakePatchTransformer( func (p *FactoryImpl) MakePatchTransformer(
slice []*resource.Resource, slice []*resource.Resource,
rf *resource.Factory) (transformers.Transformer, error) { rf *resource.Factory) (transformers.Transformer, error) {
return patch.NewPatchTransformer(slice, rf) return patch.NewTransformer(slice, rf)
} }
// MakeHashTransformer makes a new name hash transformer // MakeHashTransformer makes a new name hash transformer
func (p *FactoryImpl) MakeHashTransformer() transformers.Transformer { func (p *FactoryImpl) MakeHashTransformer() transformers.Transformer {
return hash.NewNameHashTransformer() return hash.NewTransformer()
} }
func (p *FactoryImpl) MakeInventoryTransformer( func (p *FactoryImpl) MakeInventoryTransformer(
arg *types.Inventory, arg *types.Inventory,
ldr ifc.Loader,
namespace string, namespace string,
gp types.GarbagePolicy) transformers.Transformer { gp types.GarbagePolicy) transformers.Transformer {
return inventory.NewInventoryTransformer(arg, namespace, gp) return inventory.NewTransformer(arg, ldr, namespace, gp)
} }

View File

@@ -1,184 +0,0 @@
/*
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.
*/
package hash
import (
"crypto/sha256"
"encoding/json"
"fmt"
"sort"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// KustHash compute hash for unstructured objects
type KustHash struct{}
// 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) {
u := unstructured.Unstructured{
Object: m,
}
kind := u.GetKind()
switch kind {
case "ConfigMap":
cm, err := unstructuredToConfigmap(u)
if err != nil {
return "", err
}
return ConfigMapHash(cm)
case "Secret":
sec, err := unstructuredToSecret(u)
if err != nil {
return "", err
}
return SecretHash(sec)
default:
return "", fmt.Errorf("type %s is supported for hashing in %v", kind, m)
}
}
// ConfigMapHash returns a hash of the ConfigMap.
// The Data, Kind, and Name are taken into account.
func ConfigMapHash(cm *v1.ConfigMap) (string, error) {
encoded, err := encodeConfigMap(cm)
if err != nil {
return "", err
}
h, err := encodeHash(hash(encoded))
if err != nil {
return "", err
}
return h, nil
}
// SecretHash returns a hash of the Secret.
// The Data, Kind, Name, and Type are taken into account.
func SecretHash(sec *v1.Secret) (string, error) {
encoded, err := encodeSecret(sec)
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)))
if err != nil {
return "", err
}
return h, nil
}
// encodeConfigMap encodes a ConfigMap.
// Data, Kind, and Name are taken into account.
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data}
if len(cm.BinaryData) > 0 {
m["binaryData"] = cm.BinaryData
}
data, err := json.Marshal(m)
if err != nil {
return "", err
}
return string(data), nil
}
// encodeSecret encodes a Secret.
// Data, Kind, Name, and Type are taken into account.
func encodeSecret(sec *v1.Secret) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
if err != nil {
return "", err
}
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 {
return nil, err
}
var out v1.ConfigMap
err = json.Unmarshal(marshaled, &out)
return &out, err
}
func unstructuredToSecret(u unstructured.Unstructured) (*v1.Secret, error) {
marshaled, err := json.Marshal(u.Object)
if err != nil {
return nil, err
}
var out v1.Secret
err = json.Unmarshal(marshaled, &out)
return &out, err
}

View File

@@ -0,0 +1,121 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package hash
import (
"encoding/json"
"fmt"
"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.
type kustHash struct{}
// 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) {
u := unstructured.Unstructured{
Object: m,
}
kind := u.GetKind()
switch kind {
case "ConfigMap":
cm, err := unstructuredToConfigmap(u)
if err != nil {
return "", err
}
return configMapHash(cm)
case "Secret":
sec, err := unstructuredToSecret(u)
if err != nil {
return "", err
}
return secretHash(sec)
default:
return "", fmt.Errorf(
"type %s is not supported for hashing in %v", kind, m)
}
}
// configMapHash returns a hash of the ConfigMap.
// The Data, Kind, and Name are taken into account.
func configMapHash(cm *v1.ConfigMap) (string, error) {
encoded, err := encodeConfigMap(cm)
if err != nil {
return "", err
}
h, err := hasher.Encode(hasher.Hash(encoded))
if err != nil {
return "", err
}
return h, nil
}
// SecretHash returns a hash of the Secret.
// The Data, Kind, Name, and Type are taken into account.
func secretHash(sec *v1.Secret) (string, error) {
encoded, err := encodeSecret(sec)
if err != nil {
return "", err
}
h, err := hasher.Encode(hasher.Hash(encoded))
if err != nil {
return "", err
}
return h, nil
}
// encodeConfigMap encodes a ConfigMap.
// Data, Kind, and Name are taken into account.
func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data}
if len(cm.BinaryData) > 0 {
m["binaryData"] = cm.BinaryData
}
data, err := json.Marshal(m)
if err != nil {
return "", err
}
return string(data), nil
}
// encodeSecret encodes a Secret.
// Data, Kind, Name, and Type are taken into account.
func encodeSecret(sec *v1.Secret) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
if err != nil {
return "", err
}
return string(data), nil
}
func unstructuredToConfigmap(u unstructured.Unstructured) (*v1.ConfigMap, error) {
marshaled, err := json.Marshal(u.Object)
if err != nil {
return nil, err
}
var out v1.ConfigMap
err = json.Unmarshal(marshaled, &out)
return &out, err
}
func unstructuredToSecret(u unstructured.Unstructured) (*v1.Secret, error) {
marshaled, err := json.Marshal(u.Object)
if err != nil {
return nil, err
}
var out v1.Secret
err = json.Unmarshal(marshaled, &out)
return &out, err
}

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2017 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 hash package hash
@@ -54,7 +41,7 @@ func TestConfigMapHash(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
h, err := ConfigMapHash(c.cm) h, err := configMapHash(c.cm)
if SkipRest(t, c.desc, err, c.err) { if SkipRest(t, c.desc, err, c.err) {
continue continue
} }
@@ -80,7 +67,7 @@ func TestSecretHash(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
h, err := SecretHash(c.secret) h, err := secretHash(c.secret)
if SkipRest(t, c.desc, err, c.err) { if SkipRest(t, c.desc, err, c.err) {
continue continue
} }
@@ -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) { func TestEncodeConfigMap(t *testing.T) {
cases := []struct { cases := []struct {
desc string 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 // 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 // not perfect, as it only checks the number of top-level fields
func TestTypeStability(t *testing.T) { func TestTypeStability(t *testing.T) {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 hash package hash
@@ -152,7 +139,7 @@ func TestNameHashTransformer(t *testing.T) {
}, &types.GeneratorArgs{Behavior: "create"}, &types.GeneratorOptions{DisableNameSuffixHash: false}), }, &types.GeneratorArgs{Behavior: "create"}, &types.GeneratorOptions{DisableNameSuffixHash: false}),
} }
tran := NewNameHashTransformer() tran := NewTransformer()
tran.Transform(objs) tran.Transform(objs)
if !reflect.DeepEqual(objs, expected) { if !reflect.DeepEqual(objs, expected) {

View File

@@ -5,9 +5,11 @@ package inventory
import ( import (
"fmt" "fmt"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/k8sdeps/transformer/hash"
"sigs.k8s.io/kustomize/pkg/gvk" "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/inventory"
"sigs.k8s.io/kustomize/pkg/resid" "sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
@@ -16,25 +18,28 @@ import (
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
) )
// inventoryTransformer compute the inventory object used in prune // transformer compute the inventory object used in prune
type inventoryTransformer struct { type transformer struct {
garbagePolicy types.GarbagePolicy garbagePolicy types.GarbagePolicy
ldr ifc.Loader
cmName string cmName string
cmNamespace string cmNamespace string
} }
var _ transformers.Transformer = &inventoryTransformer{} var _ transformers.Transformer = &transformer{}
// NewInventoryTransformer makes a inventoryTransformer. // NewTransformer makes a new inventory transformer.
func NewInventoryTransformer( func NewTransformer(
p *types.Inventory, p *types.Inventory,
ldr ifc.Loader,
namespace string, namespace string,
gp types.GarbagePolicy) transformers.Transformer { gp types.GarbagePolicy) transformers.Transformer {
if p == nil || p.Type != "ConfigMap" || p.ConfigMap.Namespace != namespace { if p == nil || p.Type != "ConfigMap" || p.ConfigMap.Namespace != namespace {
return transformers.NewNoOpTransformer() return transformers.NewNoOpTransformer()
} }
return &inventoryTransformer{ return &transformer{
garbagePolicy: gp, garbagePolicy: gp,
ldr: ldr,
cmName: p.ConfigMap.Name, cmName: p.ConfigMap.Name,
cmNamespace: p.ConfigMap.Namespace, cmNamespace: p.ConfigMap.Namespace,
} }
@@ -48,7 +53,7 @@ func NewInventoryTransformer(
// The inventory data is written to annotation since // The inventory data is written to annotation since
// 1. The key in data field is constrained and couldn't include arbitrary letters // 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 // 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() invty := inventory.NewInventory()
var keys []string var keys []string
for _, r := range m { for _, r := range m {
@@ -64,14 +69,14 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error {
invty.Current[item] = refs invty.Current[item] = refs
keys = append(keys, item.String()) keys = append(keys, item.String())
} }
h, err := hash.SortArrayAndComputeHash(keys) h, err := hasher.SortArrayAndComputeHash(keys)
if err != nil { if err != nil {
return err return err
} }
args := &types.ConfigMapArgs{} args := &types.ConfigMapArgs{}
args.Name = o.cmName args.Name = tf.cmName
args.Namespace = o.cmNamespace args.Namespace = tf.cmNamespace
opts := &types.GeneratorOptions{ opts := &types.GeneratorOptions{
Annotations: make(map[string]string), Annotations: make(map[string]string),
} }
@@ -82,12 +87,12 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error {
} }
kf := kunstruct.NewKunstructuredFactoryImpl() kf := kunstruct.NewKunstructuredFactoryImpl()
k, err := kf.MakeConfigMap(nil, opts, args) k, err := kf.MakeConfigMap(tf.ldr, opts, args)
if err != nil { if err != nil {
return err return err
} }
if o.garbagePolicy == types.GarbageCollect { if tf.garbagePolicy == types.GarbageCollect {
for k := range m { for k := range m {
delete(m, k) delete(m, k)
} }
@@ -98,8 +103,8 @@ func (o *inventoryTransformer) Transform(m resmap.ResMap) error {
Version: "v1", Version: "v1",
Kind: "ConfigMap", Kind: "ConfigMap",
}, },
o.cmName, tf.cmName,
"", o.cmNamespace) "", tf.cmNamespace)
if _, ok := m[id]; ok { if _, ok := m[id]; ok {
return fmt.Errorf("id %v is already used, please use a different name in the prune field", id) return fmt.Errorf("id %v is already used, please use a different name in the prune field", id)
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 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 inventory package inventory
@@ -21,11 +8,14 @@ import (
"testing" "testing"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/gvk" "sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/resid" "sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
"sigs.k8s.io/kustomize/pkg/validators"
) )
var secret = gvk.Gvk{Version: "v1", Kind: "Secret"} var secret = gvk.Gvk{Version: "v1", Kind: "Secret"}
@@ -106,6 +96,7 @@ func makeResMap() resmap.ResMap {
func TestInventoryTransformer(t *testing.T) { func TestInventoryTransformer(t *testing.T) {
rf := resource.NewFactory( rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()) kunstruct.NewKunstructuredFactoryImpl())
ldr := loader.NewFileLoaderAtCwd(validators.MakeFakeValidator(), fs.MakeFakeFS())
// hash is derived based on all keys in the Inventory // hash is derived based on all keys in the Inventory
// It is added to annotations as // It is added to annotations as
@@ -148,7 +139,7 @@ func TestInventoryTransformer(t *testing.T) {
objs := makeResMap() objs := makeResMap()
// include the original resmap; only return the ConfigMap for pruning // include the original resmap; only return the ConfigMap for pruning
tran := NewInventoryTransformer(p, "default", types.GarbageCollect) tran := NewTransformer(p, ldr, "default", types.GarbageCollect)
tran.Transform(objs) tran.Transform(objs)
if !reflect.DeepEqual(objs, expected) { if !reflect.DeepEqual(objs, expected) {
@@ -160,7 +151,7 @@ func TestInventoryTransformer(t *testing.T) {
expected = objs.DeepCopy(rf) expected = objs.DeepCopy(rf)
expected[resid.NewResIdWithPrefixNamespace(cmap, "pruneCM", "", "default")] = pruneMap expected[resid.NewResIdWithPrefixNamespace(cmap, "pruneCM", "", "default")] = pruneMap
// append the ConfigMap for pruning to the original resmap // append the ConfigMap for pruning to the original resmap
tran = NewInventoryTransformer(p, "default", types.GarbageIgnore) tran = NewTransformer(p, ldr, "default", types.GarbageIgnore)
tran.Transform(objs) tran.Transform(objs)
if !reflect.DeepEqual(objs, expected) { if !reflect.DeepEqual(objs, expected) {

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 patch package patch

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 patch package patch
@@ -31,27 +18,27 @@ import (
"sigs.k8s.io/kustomize/pkg/transformers" "sigs.k8s.io/kustomize/pkg/transformers"
) )
// patchTransformer applies patches. // transformer applies strategic merge patches.
type patchTransformer struct { type transformer struct {
patches []*resource.Resource patches []*resource.Resource
rf *resource.Factory rf *resource.Factory
} }
var _ transformers.Transformer = &patchTransformer{} var _ transformers.Transformer = &transformer{}
// NewPatchTransformer constructs a patchTransformer. // NewTransformer constructs a strategic merge patch transformer.
func NewPatchTransformer( func NewTransformer(
slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error) { slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error) {
if len(slice) == 0 { if len(slice) == 0 {
return transformers.NewNoOpTransformer(), nil 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. // 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. // Merge and then index the patches by Id.
patches, err := pt.mergePatches() patches, err := tf.mergePatches()
if err != nil { if err != nil {
return err return err
} }
@@ -118,9 +105,9 @@ func (pt *patchTransformer) Transform(baseResourceMap resmap.ResMap) error {
// mergePatches merge and index patches by Id. // mergePatches merge and index patches by Id.
// It errors out if there is conflict between patches. // 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{} rc := resmap.ResMap{}
for ix, patch := range pt.patches { for ix, patch := range tf.patches {
id := patch.Id() id := patch.Id()
existing, found := rc[id] existing, found := rc[id]
if !found { if !found {
@@ -134,9 +121,9 @@ func (pt *patchTransformer) mergePatches() (resmap.ResMap, error) {
} }
var cd conflictDetector var cd conflictDetector
if err != nil { if err != nil {
cd = newJMPConflictDetector(pt.rf) cd = newJMPConflictDetector(tf.rf)
} else { } else {
cd, err = newSMPConflictDetector(versionedObj, pt.rf) cd, err = newSMPConflictDetector(versionedObj, tf.rf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -147,7 +134,7 @@ func (pt *patchTransformer) mergePatches() (resmap.ResMap, error) {
return nil, err return nil, err
} }
if conflict { if conflict {
conflictingPatch, err := cd.findConflict(ix, pt.patches) conflictingPatch, err := cd.findConflict(ix, tf.patches)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 patch package patch
@@ -128,7 +115,7 @@ func TestOverlayRun(t *testing.T) {
}, },
}), }),
} }
lt, err := NewPatchTransformer(patch, rf) lt, err := NewTransformer(patch, rf)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) 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 { if err != nil {
t.Fatalf("unexpected error: %v", err) 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 { if err != nil {
t.Fatalf("unexpected error: %v", err) 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 { if err != nil {
t.Fatalf("unexpected error: %v", err) 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 { if err != nil {
t.Fatalf("unexpected error: %v", err) 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 { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }

View File

@@ -1,24 +1,15 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 The Kubernetes Authors. // SPDX-License-Identifier: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License"); // Package validator provides functions to validate labels, annotations,
you may not use this file except in compliance with the License. // namespaces and configmap/secret keys using apimachinery functions.
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 package validator
import ( import (
"errors" "errors"
"fmt"
"strings"
apivalidation "k8s.io/apimachinery/pkg/api/validation" apivalidation "k8s.io/apimachinery/pkg/api/validation"
v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
@@ -33,6 +24,24 @@ func NewKustValidator() *KustValidator {
return &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. // MakeAnnotationValidator returns a MapValidatorFunc using apimachinery.
func (v *KustValidator) MakeAnnotationValidator() func(map[string]string) error { func (v *KustValidator) MakeAnnotationValidator() func(map[string]string) error {
return func(x map[string]string) error { return func(x map[string]string) error {

View File

@@ -1,18 +1,5 @@
/* /// Copyright 2019 The Kubernetes Authors.
Copyright 2017 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 build package build
@@ -22,6 +9,8 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"sigs.k8s.io/kustomize/pkg/ifc"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
@@ -67,12 +56,14 @@ url examples:
// NewCmdBuild creates a new build command. // NewCmdBuild creates a new build command.
func NewCmdBuild( func NewCmdBuild(
out io.Writer, fs fs.FileSystem, out io.Writer, fSys fs.FileSystem,
rf *resmap.Factory, v ifc.Validator, rf *resmap.Factory,
ptf transformer.Factory, ptf transformer.Factory) *cobra.Command {
pl *plugins.Loader) *cobra.Command {
var o Options var o Options
pluginConfig := plugins.DefaultPluginConfig()
pl := plugins.NewLoader(pluginConfig, rf)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "build [path]", Use: "build [path]",
Short: "Print current configuration per contents of " + pgmconfig.KustomizationFileNames[0], Short: "Print current configuration per contents of " + pgmconfig.KustomizationFileNames[0],
@@ -83,16 +74,19 @@ func NewCmdBuild(
if err != nil { if err != nil {
return err return err
} }
return o.RunBuild(out, fs, rf, ptf, pl) return o.RunBuild(out, v, fSys, rf, ptf, pl)
}, },
} }
cmd.Flags().StringVarP( cmd.Flags().StringVarP(
&o.outputPath, &o.outputPath,
"output", "o", "", "output", "o", "",
"If specified, write the build output to this path.") "If specified, write the build output to this path.")
loader.AddLoadRestrictionsFlag(cmd.Flags()) loader.AddLoadRestrictionsFlag(cmd.Flags())
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 return cmd
} }
@@ -113,11 +107,11 @@ func (o *Options) Validate(args []string) (err error) {
// RunBuild runs build command. // RunBuild runs build command.
func (o *Options) RunBuild( 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, rf *resmap.Factory, ptf transformer.Factory,
pl *plugins.Loader) error { pl *plugins.Loader) error {
ldr, err := loader.NewLoader( ldr, err := loader.NewLoader(
o.loadRestrictor, o.kustomizationPath, fSys) o.loadRestrictor, v, o.kustomizationPath, fSys)
if err != nil { if err != nil {
return err return err
} }
@@ -134,11 +128,11 @@ func (o *Options) RunBuild(
} }
func (o *Options) RunBuildPrune( 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, rf *resmap.Factory, ptf transformer.Factory,
pl *plugins.Loader) error { pl *plugins.Loader) error {
ldr, err := loader.NewLoader( ldr, err := loader.NewLoader(
o.loadRestrictor, o.kustomizationPath, fSys) o.loadRestrictor, v, o.kustomizationPath, fSys)
if err != nil { if err != nil {
return err return err
} }
@@ -171,9 +165,8 @@ func (o *Options) emitResources(
} }
func NewCmdBuildPrune( func NewCmdBuildPrune(
out io.Writer, fs fs.FileSystem, out io.Writer, v ifc.Validator, fSys fs.FileSystem,
rf *resmap.Factory, rf *resmap.Factory, ptf transformer.Factory,
ptf transformer.Factory,
pl *plugins.Loader) *cobra.Command { pl *plugins.Loader) *cobra.Command {
var o Options var o Options
@@ -187,7 +180,7 @@ func NewCmdBuildPrune(
if err != nil { if err != nil {
return err return err
} }
return o.RunBuildPrune(out, fs, rf, ptf, pl) return o.RunBuildPrune(out, v, fSys, rf, ptf, pl)
}, },
} }
return cmd return cmd

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2017 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 commands holds the CLI glue mapping textual commands/args to method calls. // Package commands holds the CLI glue mapping textual commands/args to method calls.
package commands package commands
@@ -23,7 +10,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/k8sdeps/transformer" "sigs.k8s.io/kustomize/k8sdeps/transformer"
"sigs.k8s.io/kustomize/k8sdeps/validator" "sigs.k8s.io/kustomize/k8sdeps/validator"
"sigs.k8s.io/kustomize/pkg/commands/build" "sigs.k8s.io/kustomize/pkg/commands/build"
@@ -31,10 +17,8 @@ import (
"sigs.k8s.io/kustomize/pkg/commands/misc" "sigs.k8s.io/kustomize/pkg/commands/misc"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/plugins"
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/types"
) )
// NewDefaultCommand returns the default (aka root) command for kustomize command. // NewDefaultCommand returns the default (aka root) command for kustomize command.
@@ -51,28 +35,14 @@ See https://sigs.k8s.io/kustomize
`, `,
} }
pluginConfig := plugin.DefaultPluginConfig() uf := kunstruct.NewKunstructuredFactoryImpl()
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)
rf := resmap.NewFactory(resource.NewFactory(uf)) rf := resmap.NewFactory(resource.NewFactory(uf))
v := validator.NewKustValidator()
c.AddCommand( c.AddCommand(
build.NewCmdBuild( build.NewCmdBuild(
stdOut, fSys, stdOut, fSys, v,
rf, rf, transformer.NewFactoryImpl()),
transformer.NewFactoryImpl(), edit.NewCmdEdit(fSys, v, uf),
plugins.NewLoader(pluginConfig, rf)),
edit.NewCmdEdit(fSys, validator.NewKustValidator(), uf),
misc.NewCmdConfig(fSys), misc.NewCmdConfig(fSys),
misc.NewCmdVersion(stdOut), misc.NewCmdVersion(stdOut),
) )

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2017 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 add package add
@@ -23,7 +10,10 @@ import (
) )
// NewCmdAdd returns an instance of 'add' subcommand. // 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{ c := &cobra.Command{
Use: "add", Use: "add",
Short: "Adds an item to the kustomization file.", 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), Args: cobra.MinimumNArgs(1),
} }
c.AddCommand( c.AddCommand(
newCmdAddResource(fsys), newCmdAddResource(fSys),
newCmdAddPatch(fsys), newCmdAddPatch(fSys),
newCmdAddSecret(fsys, kf), newCmdAddSecret(fSys, ldr, kf),
newCmdAddConfigMap(fsys, kf), newCmdAddConfigMap(fSys, ldr, kf),
newCmdAddBase(fsys), newCmdAddBase(fSys),
newCmdAddLabel(fsys, v.MakeLabelValidator()), newCmdAddLabel(fSys, ldr.Validator().MakeLabelValidator()),
newCmdAddAnnotation(fsys, v.MakeAnnotationValidator()), newCmdAddAnnotation(fSys, ldr.Validator().MakeAnnotationValidator()),
) )
return c return c
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2017 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 add package add
@@ -21,12 +8,14 @@ import (
"sigs.k8s.io/kustomize/pkg/commands/kustfile" "sigs.k8s.io/kustomize/pkg/commands/kustfile"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
) )
// newCmdAddConfigMap returns a new command. // 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 var flags flagsAndArgs
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1]", Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1]",
@@ -65,8 +54,7 @@ func newCmdAddConfigMap(fSys fs.FileSystem, kf ifc.KunstructuredFactory) *cobra.
} }
// Add the flagsAndArgs map to the kustomization file. // Add the flagsAndArgs map to the kustomization file.
err = addConfigMap( err = addConfigMap(ldr, kustomization, flags, kf)
loader.NewFileLoaderAtCwd(fSys), kustomization, flags, kf)
if err != nil { if err != nil {
return err return err
} }
@@ -104,17 +92,17 @@ func addConfigMap(
ldr ifc.Loader, ldr ifc.Loader,
k *types.Kustomization, k *types.Kustomization,
flags flagsAndArgs, kf ifc.KunstructuredFactory) error { flags flagsAndArgs, kf ifc.KunstructuredFactory) error {
cmArgs := makeConfigMapArgs(k, flags.Name) args := findOrMakeConfigMapArgs(k, flags.Name)
mergeFlagsIntoCmArgs(&cmArgs.KVSources, flags) mergeFlagsIntoCmArgs(args, flags)
// Validate by trying to create corev1.configmap. // Validate by trying to create corev1.configmap.
_, err := kf.MakeConfigMap(ldr, k.GeneratorOptions, cmArgs) _, err := kf.MakeConfigMap(ldr, k.GeneratorOptions, args)
if err != nil { if err != nil {
return err return err
} }
return nil 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 { for i, v := range m.ConfigMapGenerator {
if name == v.Name { if name == v.Name {
return &m.ConfigMapGenerator[i] return &m.ConfigMapGenerator[i]
@@ -126,23 +114,17 @@ func makeConfigMapArgs(m *types.Kustomization, name string) *types.ConfigMapArgs
return &m.ConfigMapGenerator[len(m.ConfigMapGenerator)-1] 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 { if len(flags.LiteralSources) > 0 {
*src = append(*src, types.KVSource{ args.LiteralSources = append(
Name: "literals", args.LiteralSources, flags.LiteralSources...)
Args: flags.LiteralSources,
})
} }
if len(flags.FileSources) > 0 { if len(flags.FileSources) > 0 {
*src = append(*src, types.KVSource{ args.FileSources = append(
Name: "files", args.FileSources, flags.FileSources...)
Args: flags.FileSources,
})
} }
if flags.EnvFileSource != "" { if flags.EnvFileSource != "" {
*src = append(*src, types.KVSource{ args.EnvSources = append(
Name: "envfiles", args.EnvSources, flags.EnvFileSource)
Args: []string{flags.EnvFileSource},
})
} }
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2017 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 add package add
@@ -20,11 +7,15 @@ import (
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
"sigs.k8s.io/kustomize/pkg/validators"
) )
func TestNewAddConfigMapIsNotNil(t *testing.T) { 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") t.Fatal("newCmdAddConfigMap shouldn't be nil")
} }
} }
@@ -39,7 +30,7 @@ func TestMakeConfigMapArgs(t *testing.T) {
if len(kustomization.ConfigMapGenerator) != 0 { if len(kustomization.ConfigMapGenerator) != 0 {
t.Fatal("Initial kustomization should not have any configmaps") t.Fatal("Initial kustomization should not have any configmaps")
} }
args := makeConfigMapArgs(kustomization, cmName) args := findOrMakeConfigMapArgs(kustomization, cmName)
if args == nil { if args == nil {
t.Fatalf("args should always be non-nil") t.Fatalf("args should always be non-nil")
@@ -53,7 +44,7 @@ func TestMakeConfigMapArgs(t *testing.T) {
t.Fatalf("Pointer address for newly inserted configmap generator should be same") t.Fatalf("Pointer address for newly inserted configmap generator should be same")
} }
args2 := makeConfigMapArgs(kustomization, cmName) args2 := findOrMakeConfigMapArgs(kustomization, cmName)
if args2 != args { if args2 != args {
t.Fatalf("should have returned an existing args with name: %v", cmName) t.Fatalf("should have returned an existing args with name: %v", cmName)
@@ -64,51 +55,53 @@ func TestMakeConfigMapArgs(t *testing.T) {
} }
} }
func TestMergeFlagsIntoCmArgs_LiteralSources(t *testing.T) { func TestMergeFlagsIntoConfigMapArgs_LiteralSources(t *testing.T) {
var kv []types.KVSource k := &types.Kustomization{}
args := findOrMakeConfigMapArgs(k, "foo")
mergeFlagsIntoCmArgs(&kv, flagsAndArgs{LiteralSources: []string{"k1=v1"}}) mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
if len(kv) != 1 { flagsAndArgs{LiteralSources: []string{"k1=v1"}})
t.Fatalf("Initial literal source should have been added") mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{LiteralSources: []string{"k2=v2"}})
if k.ConfigMapGenerator[0].LiteralSources[0] != "k1=v1" {
t.Fatalf("expected v1")
} }
if k.ConfigMapGenerator[0].LiteralSources[1] != "k2=v2" {
mergeFlagsIntoCmArgs(&kv, flagsAndArgs{LiteralSources: []string{"k2=v2"}}) t.Fatalf("expected v2")
if len(kv) != 2 {
t.Fatalf("Second literal source should have been added")
} }
} }
func TestMergeFlagsIntoCmArgs_FileSources(t *testing.T) { func TestMergeFlagsIntoConfigMapArgs_FileSources(t *testing.T) {
var kv []types.KVSource k := &types.Kustomization{}
args := findOrMakeConfigMapArgs(k, "foo")
mergeFlagsIntoCmArgs(&kv, flagsAndArgs{FileSources: []string{"file1"}}) mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
if len(kv) != 1 { flagsAndArgs{FileSources: []string{"file1"}})
t.Fatalf("Initial file source should have been added") mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{FileSources: []string{"file2"}})
if k.ConfigMapGenerator[0].FileSources[0] != "file1" {
t.Fatalf("expected file1")
} }
if k.ConfigMapGenerator[0].FileSources[1] != "file2" {
mergeFlagsIntoCmArgs(&kv, flagsAndArgs{FileSources: []string{"file2"}}) t.Fatalf("expected file2")
if len(kv) != 2 {
t.Fatalf("Second file source should have been added")
} }
} }
func TestMergeFlagsIntoCmArgs_EnvSource(t *testing.T) { func TestMergeFlagsIntoConfigMapArgs_EnvSource(t *testing.T) {
envFileName := "env1" k := &types.Kustomization{}
envFileName2 := "env2" args := findOrMakeConfigMapArgs(k, "foo")
var kv []types.KVSource mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
mergeFlagsIntoCmArgs(&kv, flagsAndArgs{EnvFileSource: envFileName}) flagsAndArgs{EnvFileSource: "env1"})
mergeFlagsIntoGeneratorArgs(
if len(kv) != 1 { &args.GeneratorArgs,
t.Fatalf("Initial env source should have been added") flagsAndArgs{EnvFileSource: "env2"})
if k.ConfigMapGenerator[0].EnvSources[0] != "env1" {
t.Fatalf("expected env1")
} }
if k.ConfigMapGenerator[0].EnvSources[1] != "env2" {
mergeFlagsIntoCmArgs(&kv, flagsAndArgs{EnvFileSource: envFileName2}) t.Fatalf("expected env2")
if len(kv) != 2 {
t.Fatalf("Second env source should have been added")
} }
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 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 add package add
@@ -21,12 +8,14 @@ import (
"sigs.k8s.io/kustomize/pkg/commands/kustfile" "sigs.k8s.io/kustomize/pkg/commands/kustfile"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
) )
// newCmdAddSecret returns a new command. // 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 var flags flagsAndArgs
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "secret NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--type=Opaque|kubernetes.io/tls]", Use: "secret NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--type=Opaque|kubernetes.io/tls]",
@@ -65,8 +54,7 @@ func newCmdAddSecret(fSys fs.FileSystem, kf ifc.KunstructuredFactory) *cobra.Com
} }
// Add the flagsAndArgs map to the kustomization file. // Add the flagsAndArgs map to the kustomization file.
err = addSecret( err = addSecret(ldr, kustomization, flags, kf)
loader.NewFileLoaderAtCwd(fSys), kustomization, flags, kf)
if err != nil { if err != nil {
return err return err
} }
@@ -109,45 +97,41 @@ func addSecret(
ldr ifc.Loader, ldr ifc.Loader,
k *types.Kustomization, k *types.Kustomization,
flags flagsAndArgs, kf ifc.KunstructuredFactory) error { flags flagsAndArgs, kf ifc.KunstructuredFactory) error {
secretArgs := makeSecretArgs(k, flags.Name, flags.Type) args := findOrMakeSecretArgs(k, flags.Name, flags.Type)
mergeFlagsIntoSecretArgs(&secretArgs.KVSources, flags) mergeFlagsIntoGeneratorArgs(&args.GeneratorArgs, flags)
// Validate by trying to create corev1.secret. // Validate by trying to create corev1.secret.
_, err := kf.MakeSecret(ldr, k.GeneratorOptions, secretArgs) _, err := kf.MakeSecret(ldr, k.GeneratorOptions, args)
if err != nil { if err != nil {
return err return err
} }
return nil 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 { for i, v := range m.SecretGenerator {
if name == v.Name { if name == v.Name {
return &m.SecretGenerator[i] return &m.SecretGenerator[i]
} }
} }
// secret not found, create new one and add it to the kustomization file. // 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) m.SecretGenerator = append(m.SecretGenerator, *secret)
return &m.SecretGenerator[len(m.SecretGenerator)-1] 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 { if len(flags.LiteralSources) > 0 {
*src = append(*src, types.KVSource{ args.LiteralSources = append(
Name: "literals", args.LiteralSources, flags.LiteralSources...)
Args: flags.LiteralSources,
})
} }
if len(flags.FileSources) > 0 { if len(flags.FileSources) > 0 {
*src = append(*src, types.KVSource{ args.FileSources = append(
Name: "files", args.FileSources, flags.FileSources...)
Args: flags.FileSources,
})
} }
if flags.EnvFileSource != "" { if flags.EnvFileSource != "" {
*src = append(*src, types.KVSource{ args.EnvSources = append(
Name: "envfiles", args.EnvSources, flags.EnvFileSource)
Args: []string{flags.EnvFileSource},
})
} }
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 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 add package add
@@ -20,11 +7,15 @@ import (
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
"sigs.k8s.io/kustomize/pkg/validators"
) )
func TestNewCmdAddSecretIsNotNil(t *testing.T) { 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") t.Fatal("newCmdAddSecret shouldn't be nil")
} }
} }
@@ -41,7 +32,7 @@ func TestMakeSecretArgs(t *testing.T) {
if len(kustomization.SecretGenerator) != 0 { if len(kustomization.SecretGenerator) != 0 {
t.Fatal("Initial kustomization should not have any secrets") t.Fatal("Initial kustomization should not have any secrets")
} }
args := makeSecretArgs(kustomization, secretName, secretType) args := findOrMakeSecretArgs(kustomization, secretName, secretType)
if args == nil { if args == nil {
t.Fatalf("args should always be non-nil") t.Fatalf("args should always be non-nil")
@@ -55,7 +46,7 @@ func TestMakeSecretArgs(t *testing.T) {
t.Fatalf("Pointer address for newly inserted secret generator should be same") 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 { if args2 != args {
t.Fatalf("should have returned an existing args with name: %v", secretName) t.Fatalf("should have returned an existing args with name: %v", secretName)
@@ -67,50 +58,52 @@ func TestMakeSecretArgs(t *testing.T) {
} }
func TestMergeFlagsIntoSecretArgs_LiteralSources(t *testing.T) { func TestMergeFlagsIntoSecretArgs_LiteralSources(t *testing.T) {
var kv []types.KVSource k := &types.Kustomization{}
args := findOrMakeSecretArgs(k, "foo", "forbidden")
mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{LiteralSources: []string{"k1=v1"}}) mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
if len(kv) != 1 { flagsAndArgs{LiteralSources: []string{"k1=v1"}})
t.Fatalf("Initial literal source should have been added") mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{LiteralSources: []string{"k2=v2"}})
if k.SecretGenerator[0].LiteralSources[0] != "k1=v1" {
t.Fatalf("expected v1")
} }
if k.SecretGenerator[0].LiteralSources[1] != "k2=v2" {
mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{LiteralSources: []string{"k2=v2"}}) t.Fatalf("expected v2")
if len(kv) != 2 {
t.Fatalf("Second literal source should have been added")
} }
} }
func TestMergeFlagsIntoSecretArgs_FileSources(t *testing.T) { func TestMergeFlagsIntoSecretArgs_FileSources(t *testing.T) {
var kv []types.KVSource k := &types.Kustomization{}
args := findOrMakeSecretArgs(k, "foo", "forbidden")
mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{FileSources: []string{"file1"}}) mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
if len(kv) != 1 { flagsAndArgs{FileSources: []string{"file1"}})
t.Fatalf("Initial file source should have been added") mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{FileSources: []string{"file2"}})
if k.SecretGenerator[0].FileSources[0] != "file1" {
t.Fatalf("expected file1")
} }
if k.SecretGenerator[0].FileSources[1] != "file2" {
mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{FileSources: []string{"file2"}}) t.Fatalf("expected file2")
if len(kv) != 2 {
t.Fatalf("Second file source should have been added")
} }
} }
func TestMergeFlagsIntoSecretArgs_EnvSource(t *testing.T) { func TestMergeFlagsIntoSecretArgs_EnvSource(t *testing.T) {
envFileName := "env1" k := &types.Kustomization{}
envFileName2 := "env2" args := findOrMakeSecretArgs(k, "foo", "forbidden")
var kv []types.KVSource mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{EnvFileSource: envFileName}) flagsAndArgs{EnvFileSource: "env1"})
mergeFlagsIntoGeneratorArgs(
if len(kv) != 1 { &args.GeneratorArgs,
t.Fatalf("Initial env source should have been added") flagsAndArgs{EnvFileSource: "env2"})
if k.SecretGenerator[0].EnvSources[0] != "env1" {
t.Fatalf("expected env1")
} }
if k.SecretGenerator[0].EnvSources[1] != "env2" {
mergeFlagsIntoSecretArgs(&kv, flagsAndArgs{EnvFileSource: envFileName2}) t.Fatalf("expected env2")
if len(kv) != 2 {
t.Fatalf("Second env source should have been added")
} }
} }

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2017 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 edit package edit
@@ -24,10 +11,12 @@ import (
"sigs.k8s.io/kustomize/pkg/commands/edit/set" "sigs.k8s.io/kustomize/pkg/commands/edit/set"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/loader"
) )
// NewCmdEdit returns an instance of 'edit' subcommand. // 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{ c := &cobra.Command{
Use: "edit", Use: "edit",
Short: "Edits a kustomization file", Short: "Edits a kustomization file",
@@ -44,11 +33,12 @@ func NewCmdEdit(fsys fs.FileSystem, v ifc.Validator, kf ifc.KunstructuredFactory
`, `,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
} }
c.AddCommand( c.AddCommand(
add.NewCmdAdd(fsys, v, kf), add.NewCmdAdd(fSys, loader.NewFileLoaderAtCwd(v, fSys), kf),
set.NewCmdSet(fsys, v), set.NewCmdSet(fSys, v),
fix.NewCmdFix(fsys), fix.NewCmdFix(fSys),
remove.NewCmdRemove(fsys), remove.NewCmdRemove(fSys),
) )
return c return c
} }

52
pkg/hasher/hasher.go Normal file
View File

@@ -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)))
}

41
pkg/hasher/hasher_test.go Normal file
View File

@@ -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)
}
}

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 ifc holds miscellaneous interfaces used by kustomize. // Package ifc holds miscellaneous interfaces used by kustomize.
package ifc package ifc
@@ -27,6 +14,8 @@ type Validator interface {
MakeAnnotationValidator() func(map[string]string) error MakeAnnotationValidator() func(map[string]string) error
MakeLabelValidator() func(map[string]string) error MakeLabelValidator() func(map[string]string) error
ValidateNamespace(string) []string ValidateNamespace(string) []string
ErrIfInvalidKey(string) error
IsEnvVarName(k string) error
} }
// Loader interface exposes methods to read bytes. // Loader interface exposes methods to read bytes.
@@ -39,6 +28,10 @@ type Loader interface {
Load(location string) ([]byte, error) Load(location string) ([]byte, error)
// Cleanup cleans the loader // Cleanup cleans the loader
Cleanup() error 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 // Kunstructured allows manipulation of k8s objects

View File

@@ -1,23 +1,11 @@
/* /// Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 patch holds miscellaneous interfaces used by kustomize. // Package patch holds miscellaneous interfaces used by kustomize.
package transformer package transformer
import ( import (
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/transformers" "sigs.k8s.io/kustomize/pkg/transformers"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
@@ -29,6 +17,7 @@ type Factory interface {
MakeHashTransformer() transformers.Transformer MakeHashTransformer() transformers.Transformer
MakeInventoryTransformer( MakeInventoryTransformer(
p *types.Inventory, p *types.Inventory,
ldr ifc.Loader,
namespace string, namespace string,
gp types.GarbagePolicy) transformers.Transformer gp types.GarbagePolicy) transformers.Transformer
} }

View File

@@ -11,7 +11,6 @@ import (
"sigs.k8s.io/kustomize/internal/loadertest" "sigs.k8s.io/kustomize/internal/loadertest"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/k8sdeps/transformer" "sigs.k8s.io/kustomize/k8sdeps/transformer"
"sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/pgmconfig"
@@ -33,12 +32,12 @@ type KustTestHarness struct {
func NewKustTestHarness(t *testing.T, path string) *KustTestHarness { func NewKustTestHarness(t *testing.T, path string) *KustTestHarness {
return NewKustTestHarnessWithPluginConfig( return NewKustTestHarnessWithPluginConfig(
t, path, plugin.DefaultPluginConfig()) t, path, plugins.DefaultPluginConfig())
} }
func NewKustTestPluginHarness(t *testing.T, path string) *KustTestHarness { func NewKustTestPluginHarness(t *testing.T, path string) *KustTestHarness {
return NewKustTestHarnessWithPluginConfig( return NewKustTestHarnessWithPluginConfig(
t, path, plugin.ActivePluginConfig()) t, path, plugins.ActivePluginConfig())
} }
func NewKustTestHarnessWithPluginConfig( func NewKustTestHarnessWithPluginConfig(
@@ -51,8 +50,7 @@ func NewKustTestHarnessFull(
t *testing.T, path string, t *testing.T, path string,
lr loader.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness { lr loader.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness {
rf := resmap.NewFactory(resource.NewFactory( rf := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryWithGeneratorArgs( kunstruct.NewKunstructuredFactoryImpl()))
&types.GeneratorMetaArgs{PluginConfig: pc})))
return &KustTestHarness{ return &KustTestHarness{
t: t, t: t,
rf: rf, rf: rf,

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 loader package loader
@@ -92,6 +79,9 @@ type fileLoader struct {
// Restricts behavior of Load function. // Restricts behavior of Load function.
loadRestrictor LoadRestrictorFunc loadRestrictor LoadRestrictorFunc
// Used to validate various k8s data fields.
validator ifc.Validator
// If this is non-nil, the files were // If this is non-nil, the files were
// obtained from the given repository. // obtained from the given repository.
repoSpec *git.RepoSpec repoSpec *git.RepoSpec
@@ -110,41 +100,44 @@ const CWD = "."
// NewFileLoaderAtCwd returns a loader that loads from ".". // NewFileLoaderAtCwd returns a loader that loads from ".".
// A convenience for kustomize edit commands. // A convenience for kustomize edit commands.
func NewFileLoaderAtCwd(fSys fs.FileSystem) *fileLoader { func NewFileLoaderAtCwd(v ifc.Validator, fSys fs.FileSystem) *fileLoader {
return newLoaderOrDie( return newLoaderOrDie(
RestrictionRootOnly, fSys, CWD) RestrictionRootOnly, v, fSys, CWD)
} }
// NewFileLoaderAtRoot returns a loader that loads from "/". // NewFileLoaderAtRoot returns a loader that loads from "/".
// A convenience for tests. // A convenience for tests.
func NewFileLoaderAtRoot(fSys fs.FileSystem) *fileLoader { func NewFileLoaderAtRoot(v ifc.Validator, fSys fs.FileSystem) *fileLoader {
return newLoaderOrDie( return newLoaderOrDie(
RestrictionRootOnly, fSys, string(filepath.Separator)) RestrictionRootOnly, v, fSys, string(filepath.Separator))
} }
// Root returns the absolute path that is prepended to any // Root returns the absolute path that is prepended to any
// relative paths used in Load. // relative paths used in Load.
func (l *fileLoader) Root() string { func (fl *fileLoader) Root() string {
return l.root.String() return fl.root.String()
} }
func newLoaderOrDie( 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) root, err := demandDirectoryRoot(fSys, path)
if err != nil { if err != nil {
log.Fatalf("unable to make loader at '%s'; %v", path, err) log.Fatalf("unable to make loader at '%s'; %v", path, err)
} }
return newLoaderAtConfirmedDir( return newLoaderAtConfirmedDir(
lr, root, fSys, nil, git.ClonerUsingGitExec) lr, v, root, fSys, nil, git.ClonerUsingGitExec)
} }
// newLoaderAtConfirmedDir returns a new fileLoader with given root. // newLoaderAtConfirmedDir returns a new fileLoader with given root.
func newLoaderAtConfirmedDir( func newLoaderAtConfirmedDir(
lr LoadRestrictorFunc, lr LoadRestrictorFunc,
v ifc.Validator,
root fs.ConfirmedDir, fSys fs.FileSystem, root fs.ConfirmedDir, fSys fs.FileSystem,
referrer *fileLoader, cloner git.Cloner) *fileLoader { referrer *fileLoader, cloner git.Cloner) *fileLoader {
return &fileLoader{ return &fileLoader{
loadRestrictor: lr, loadRestrictor: lr,
validator: v,
root: root, root: root,
referrer: referrer, referrer: referrer,
fSys: fSys, fSys: fSys,
@@ -175,39 +168,41 @@ func demandDirectoryRoot(
// New returns a new Loader, rooted relative to current loader, // New returns a new Loader, rooted relative to current loader,
// or rooted in a temp directory holding a git repo clone. // 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 == "" { if path == "" {
return nil, fmt.Errorf("new root cannot be empty") return nil, fmt.Errorf("new root cannot be empty")
} }
repoSpec, err := git.NewRepoSpecFromUrl(path) repoSpec, err := git.NewRepoSpecFromUrl(path)
if err == nil { if err == nil {
// Treat this as git repo clone request. // 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 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) { if filepath.IsAbs(path) {
return nil, fmt.Errorf("new root '%s' cannot be absolute", 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 { if err != nil {
return nil, err return nil, err
} }
if err := l.errIfGitContainmentViolation(root); err != nil { if err := fl.errIfGitContainmentViolation(root); err != nil {
return nil, err return nil, err
} }
if err := l.errIfArgEqualOrHigher(root); err != nil { if err := fl.errIfArgEqualOrHigher(root); err != nil {
return nil, err return nil, err
} }
return newLoaderAtConfirmedDir( 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 // newLoaderAtGitClone returns a new Loader pinned to a temporary
// directory holding a cloned git repo. // directory holding a cloned git repo.
func newLoaderAtGitClone( 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) { referrer *fileLoader, cloner git.Cloner) (ifc.Loader, error) {
err := cloner(repoSpec) err := cloner(repoSpec)
if err != nil { if err != nil {
@@ -229,6 +224,7 @@ func newLoaderAtGitClone(
return &fileLoader{ return &fileLoader{
// Clones never allowed to escape root. // Clones never allowed to escape root.
loadRestrictor: RestrictionRootOnly, loadRestrictor: RestrictionRootOnly,
validator: v,
root: root, root: root,
referrer: referrer, referrer: referrer,
repoSpec: repoSpec, repoSpec: repoSpec,
@@ -238,9 +234,9 @@ func newLoaderAtGitClone(
}, nil }, nil
} }
func (l *fileLoader) errIfGitContainmentViolation( func (fl *fileLoader) errIfGitContainmentViolation(
base fs.ConfirmedDir) error { base fs.ConfirmedDir) error {
containingRepo := l.containingRepo() containingRepo := fl.containingRepo()
if containingRepo == nil { if containingRepo == nil {
return nil return nil
} }
@@ -256,64 +252,64 @@ func (l *fileLoader) errIfGitContainmentViolation(
// Looks back through referrers for a git repo, returning nil // Looks back through referrers for a git repo, returning nil
// if none found. // if none found.
func (l *fileLoader) containingRepo() *git.RepoSpec { func (fl *fileLoader) containingRepo() *git.RepoSpec {
if l.repoSpec != nil { if fl.repoSpec != nil {
return l.repoSpec return fl.repoSpec
} }
if l.referrer == nil { if fl.referrer == nil {
return nil return nil
} }
return l.referrer.containingRepo() return fl.referrer.containingRepo()
} }
// errIfArgEqualOrHigher tests whether the argument, // errIfArgEqualOrHigher tests whether the argument,
// is equal to or above the root of any ancestor. // is equal to or above the root of any ancestor.
func (l *fileLoader) errIfArgEqualOrHigher( func (fl *fileLoader) errIfArgEqualOrHigher(
candidateRoot fs.ConfirmedDir) error { candidateRoot fs.ConfirmedDir) error {
if l.root.HasPrefix(candidateRoot) { if fl.root.HasPrefix(candidateRoot) {
return fmt.Errorf( return fmt.Errorf(
"cycle detected: candidate root '%s' contains visited root '%s'", "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 nil
} }
return l.referrer.errIfArgEqualOrHigher(candidateRoot) return fl.referrer.errIfArgEqualOrHigher(candidateRoot)
} }
// TODO(monopole): Distinguish branches? // TODO(monopole): Distinguish branches?
// I.e. Allow a distinction between git URI with // I.e. Allow a distinction between git URI with
// path foo and tag bar and a git URI with the same // path foo and tag bar and a git URI with the same
// path but a different tag? // 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(). // TODO(monopole): Use parsed data instead of Raw().
if l.repoSpec != nil && if fl.repoSpec != nil &&
strings.HasPrefix(l.repoSpec.Raw(), newRepoSpec.Raw()) { strings.HasPrefix(fl.repoSpec.Raw(), newRepoSpec.Raw()) {
return fmt.Errorf( return fmt.Errorf(
"cycle detected: URI '%s' referenced by previous URI '%s'", "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 nil
} }
return l.referrer.errIfRepoCycle(newRepoSpec) return fl.referrer.errIfRepoCycle(newRepoSpec)
} }
// Load returns the content of file at the given path, // Load returns the content of file at the given path,
// else an error. Relative paths are taken relative // else an error. Relative paths are taken relative
// to the root. // to the root.
func (l *fileLoader) Load(path string) ([]byte, error) { func (fl *fileLoader) Load(path string) ([]byte, error) {
if !filepath.IsAbs(path) { 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 { if err != nil {
return nil, err return nil, err
} }
return l.fSys.ReadFile(path) return fl.fSys.ReadFile(path)
} }
// Cleanup runs the cleaner. // Cleanup runs the cleaner.
func (l *fileLoader) Cleanup() error { func (fl *fileLoader) Cleanup() error {
return l.cleaner() return fl.cleaner()
} }

View File

@@ -29,6 +29,7 @@ import (
"sigs.k8s.io/kustomize/pkg/git" "sigs.k8s.io/kustomize/pkg/git"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/validators"
) )
type testData struct { type testData struct {
@@ -63,8 +64,12 @@ func MakeFakeFs(td []testData) fs.FileSystem {
return fSys return fSys
} }
func makeLoader() *fileLoader {
return NewFileLoaderAtRoot(validators.MakeFakeValidator(), MakeFakeFs(testCases))
}
func TestLoaderLoad(t *testing.T) { func TestLoaderLoad(t *testing.T) {
l1 := NewFileLoaderAtRoot(MakeFakeFs(testCases)) l1 := makeLoader()
if "/" != l1.Root() { if "/" != l1.Root() {
t.Fatalf("incorrect root: '%s'\n", l1.Root()) t.Fatalf("incorrect root: '%s'\n", l1.Root())
} }
@@ -103,7 +108,7 @@ func TestLoaderLoad(t *testing.T) {
} }
func TestLoaderNewSubDir(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 { if err != nil {
t.Fatalf("unexpected err: %v\n", err) t.Fatalf("unexpected err: %v\n", err)
} }
@@ -125,7 +130,7 @@ func TestLoaderNewSubDir(t *testing.T) {
} }
func TestLoaderBadRelative(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 { if err != nil {
t.Fatalf("unexpected err: %v\n", err) t.Fatalf("unexpected err: %v\n", err)
} }
@@ -195,7 +200,7 @@ func TestLoaderBadRelative(t *testing.T) {
} }
func TestLoaderMisc(t *testing.T) { func TestLoaderMisc(t *testing.T) {
l := NewFileLoaderAtRoot(MakeFakeFs(testCases)) l := makeLoader()
_, err := l.New("") _, err := l.New("")
if err == nil { if err == nil {
t.Fatalf("Expected error for empty root location not returned") t.Fatalf("Expected error for empty root location not returned")
@@ -297,7 +302,8 @@ func TestRestrictionRootOnlyInRealLoader(t *testing.T) {
var l ifc.Loader var l ifc.Loader
l = newLoaderOrDie(RestrictionRootOnly, fSys, dir) l = newLoaderOrDie(
RestrictionRootOnly, validators.MakeFakeValidator(), fSys, dir)
l = doSanityChecksAndDropIntoBase(t, l) l = doSanityChecksAndDropIntoBase(t, l)
@@ -330,7 +336,8 @@ func TestRestrictionNoneInRealLoader(t *testing.T) {
var l ifc.Loader var l ifc.Loader
l = newLoaderOrDie(RestrictionNone, fSys, dir) l = newLoaderOrDie(
RestrictionNone, validators.MakeFakeValidator(), fSys, dir)
l = doSanityChecksAndDropIntoBase(t, l) l = doSanityChecksAndDropIntoBase(t, l)
@@ -392,7 +399,7 @@ whatever
t.Fatalf("unexpected err: %v\n", err) t.Fatalf("unexpected err: %v\n", err)
} }
l, err := newLoaderAtGitClone( l, err := newLoaderAtGitClone(
repoSpec, fSys, nil, repoSpec, validators.MakeFakeValidator(), fSys, nil,
git.DoNothingCloner(fs.ConfirmedDir(coRoot))) git.DoNothingCloner(fs.ConfirmedDir(coRoot)))
if err != nil { if err != nil {
t.Fatalf("unexpected err: %v\n", err) t.Fatalf("unexpected err: %v\n", err)
@@ -434,7 +441,8 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) {
// Establish that a local overlay can navigate // Establish that a local overlay can navigate
// to the local bases. // 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" { if l1.Root() != cloneRoot+"/foo/overlay" {
t.Fatalf("unexpected root %s", l1.Root()) t.Fatalf("unexpected root %s", l1.Root())
} }
@@ -470,7 +478,7 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) {
t.Fatalf("unexpected err: %v\n", err) t.Fatalf("unexpected err: %v\n", err)
} }
l1, err = newLoaderAtGitClone( l1, err = newLoaderAtGitClone(
repoSpec, fSys, nil, repoSpec, validators.MakeFakeValidator(), fSys, nil,
git.DoNothingCloner(fs.ConfirmedDir(cloneRoot))) git.DoNothingCloner(fs.ConfirmedDir(cloneRoot)))
if err != nil { if err != nil {
t.Fatalf("unexpected err: %v\n", err) t.Fatalf("unexpected err: %v\n", err)
@@ -509,7 +517,7 @@ func TestLocalLoaderReferencingGitBase(t *testing.T) {
t.Fatalf("unexpected err: %v\n", err) t.Fatalf("unexpected err: %v\n", err)
} }
l1 := newLoaderAtConfirmedDir( l1 := newLoaderAtConfirmedDir(
RestrictionRootOnly, root, fSys, nil, RestrictionRootOnly, validators.MakeFakeValidator(), root, fSys, nil,
git.DoNothingCloner(fs.ConfirmedDir(cloneRoot))) git.DoNothingCloner(fs.ConfirmedDir(cloneRoot)))
if l1.Root() != topDir { if l1.Root() != topDir {
t.Fatalf("unexpected root %s", l1.Root()) t.Fatalf("unexpected root %s", l1.Root())

200
pkg/loader/kv.go Normal file
View File

@@ -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
}

91
pkg/loader/kv_test.go Normal file
View File

@@ -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)
}
}
}

View File

@@ -31,17 +31,18 @@ import (
// the remote bases will all be root-only restricted. // the remote bases will all be root-only restricted.
func NewLoader( func NewLoader(
lr LoadRestrictorFunc, lr LoadRestrictorFunc,
v ifc.Validator,
target string, fSys fs.FileSystem) (ifc.Loader, error) { target string, fSys fs.FileSystem) (ifc.Loader, error) {
repoSpec, err := git.NewRepoSpecFromUrl(target) repoSpec, err := git.NewRepoSpecFromUrl(target)
if err == nil { if err == nil {
// The target qualifies as a remote git target. // The target qualifies as a remote git target.
return newLoaderAtGitClone( return newLoaderAtGitClone(
repoSpec, fSys, nil, git.ClonerUsingGitExec) repoSpec, v, fSys, nil, git.ClonerUsingGitExec)
} }
root, err := demandDirectoryRoot(fSys, target) root, err := demandDirectoryRoot(fSys, target)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newLoaderAtConfirmedDir( return newLoaderAtConfirmedDir(
lr, root, fSys, nil, git.ClonerUsingGitExec), nil lr, v, root, fSys, nil, git.ClonerUsingGitExec), nil
} }

View File

@@ -24,7 +24,6 @@ import (
"strings" "strings"
"time" "time"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/pgmconfig"
) )
@@ -56,7 +55,7 @@ func DefaultSrcRoot() (string, error) {
} }
nope = append(nope, root) nope = append(nope, root)
root = plugin.DefaultPluginConfig().DirectoryPath root = DefaultPluginConfig().DirectoryPath
if FileExists(root) { if FileExists(root) {
return root, nil return root, nil
} }

View File

@@ -1,19 +1,53 @@
/* // Copyright 2019 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 plugins 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 NotEnabledErr(name string) error {
return fmt.Errorf(
flagErrorFmt,
name,
flagEnablePluginsName,
flagEnablePluginsHelp)
}
func AddEnablePluginsFlag(set *pflag.FlagSet, v *bool) {
set.BoolVar(
v, flagEnablePluginsName,
false, flagEnablePluginsHelp)
}

View File

@@ -22,7 +22,6 @@ import (
"sigs.k8s.io/kustomize/internal/loadertest" "sigs.k8s.io/kustomize/internal/loadertest"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
) )
@@ -52,7 +51,7 @@ s/$BAR/bar/g
p := NewExecPlugin( p := NewExecPlugin(
AbsolutePluginPath( AbsolutePluginPath(
plugin.DefaultPluginConfig(), DefaultPluginConfig(),
pluginConfig.Id())) pluginConfig.Id()))
yaml, err := pluginConfig.AsYAML() yaml, err := pluginConfig.AsYAML()

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 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 plugins package plugins
@@ -115,9 +102,8 @@ func (l *Loader) absolutePluginPath(id resid.ResId) string {
func (l *Loader) loadAndConfigurePlugin( func (l *Loader) loadAndConfigurePlugin(
ldr ifc.Loader, res *resource.Resource) (c Configurable, err error) { ldr ifc.Loader, res *resource.Resource) (c Configurable, err error) {
if !l.pc.GoEnabled { if !l.pc.Enabled {
return nil, errors.Errorf( return nil, NotEnabledErr(res.Id().Gvk().Kind)
"plugins not enabled, but trying to load %s", res.Id())
} }
if p := NewExecPlugin( if p := NewExecPlugin(
l.absolutePluginPath(res.Id())); p.isAvailable() { l.absolutePluginPath(res.Id())); p.isAvailable() {

View File

@@ -8,8 +8,7 @@ import (
"sigs.k8s.io/kustomize/internal/loadertest" "sigs.k8s.io/kustomize/internal/loadertest"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "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/resmap"
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/plugin" "sigs.k8s.io/kustomize/plugin"
@@ -54,7 +53,7 @@ func TestLoader(t *testing.T) {
rmF := resmap.NewFactory(resource.NewFactory( rmF := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())) kunstruct.NewKunstructuredFactoryImpl()))
l := plugins.NewLoader(kvplugin.ActivePluginConfig(), rmF) l := NewLoader(ActivePluginConfig(), rmF)
if l == nil { if l == nil {
t.Fatal("expect non-nil loader") t.Fatal("expect non-nil loader")
} }

View File

@@ -29,6 +29,7 @@ import (
"sigs.k8s.io/kustomize/pkg/resid" "sigs.k8s.io/kustomize/pkg/resid"
. "sigs.k8s.io/kustomize/pkg/resmap" . "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
"sigs.k8s.io/kustomize/pkg/validators"
) )
func TestFromFile(t *testing.T) { func TestFromFile(t *testing.T) {
@@ -52,7 +53,6 @@ metadata:
namespace: test namespace: test
--- ---
` `
l := loadertest.NewFakeLoader("/whatever/project") l := loadertest.NewFakeLoader("/whatever/project")
if ferr := l.AddFile("/whatever/project/deployment.yaml", []byte(resourceStr)); ferr != nil { if ferr := l.AddFile("/whatever/project/deployment.yaml", []byte(resourceStr)); ferr != nil {
t.Fatalf("Error adding fake file: %v\n", ferr) t.Fatalf("Error adding fake file: %v\n", ferr)
@@ -173,6 +173,7 @@ func TestNewFromConfigMaps(t *testing.T) {
}, &types.GeneratorArgs{}, nil), }, &types.GeneratorArgs{}, nil),
}, },
}, },
{ {
description: "construct config map from file", description: "construct config map from file",
input: []types.ConfigMapArgs{{ input: []types.ConfigMapArgs{{
@@ -231,6 +232,7 @@ BAR=baz
}, &types.GeneratorArgs{}, nil), }, &types.GeneratorArgs{}, nil),
}, },
}, },
// TODO: add testcase for data coming from multiple sources like // TODO: add testcase for data coming from multiple sources like
// files/literal/env etc. // files/literal/env etc.
} }
@@ -268,7 +270,7 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
fakeFs := fs.MakeFakeFS() fakeFs := fs.MakeFakeFS()
fakeFs.Mkdir(".") fakeFs.Mkdir(".")
actual, err := rmF.NewResMapFromSecretArgs( actual, err := rmF.NewResMapFromSecretArgs(
loader.NewFileLoaderAtRoot(fakeFs), nil, secrets) loader.NewFileLoaderAtRoot(validators.MakeFakeValidator(), fakeFs), nil, secrets)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }

View File

@@ -17,10 +17,10 @@ limitations under the License.
package target_test package target_test
import ( import (
"sigs.k8s.io/kustomize/pkg/plugins"
"strings" "strings"
"testing" "testing"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/kusttest" "sigs.k8s.io/kustomize/pkg/kusttest"
"sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/loader"
) )
@@ -225,7 +225,7 @@ spec:
func TestSharedPatchDisAllowed(t *testing.T) { func TestSharedPatchDisAllowed(t *testing.T) {
th := kusttest_test.NewKustTestHarnessFull( th := kusttest_test.NewKustTestHarnessFull(
t, "/app/overlay", t, "/app/overlay",
loader.RestrictionRootOnly, plugin.DefaultPluginConfig()) loader.RestrictionRootOnly, plugins.DefaultPluginConfig())
writeSmallBase(th) writeSmallBase(th)
th.WriteK("/app/overlay", ` th.WriteK("/app/overlay", `
commonLabels: commonLabels:
@@ -257,7 +257,7 @@ spec:
func TestSharedPatchAllowed(t *testing.T) { func TestSharedPatchAllowed(t *testing.T) {
th := kusttest_test.NewKustTestHarnessFull( th := kusttest_test.NewKustTestHarnessFull(
t, "/app/overlay", t, "/app/overlay",
loader.RestrictionNone, plugin.DefaultPluginConfig()) loader.RestrictionNone, plugins.DefaultPluginConfig())
writeSmallBase(th) writeSmallBase(th)
th.WriteK("/app/overlay", ` th.WriteK("/app/overlay", `
commonLabels: commonLabels:

View File

@@ -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)
}

View File

@@ -61,7 +61,7 @@ kind: Secret
metadata: metadata:
labels: labels:
app: release-name-minecraft app: release-name-minecraft
chart: minecraft-1.0.0 chart: minecraft-1.0.1
heritage: Tiller heritage: Tiller
release: release-name release: release-name
name: LOOOOOOOONG-release-name-minecraft name: LOOOOOOOONG-release-name-minecraft
@@ -72,7 +72,7 @@ kind: Service
metadata: metadata:
labels: labels:
app: release-name-minecraft app: release-name-minecraft
chart: minecraft-1.0.0 chart: minecraft-1.0.1
heritage: Tiller heritage: Tiller
release: release-name release: release-name
name: LOOOOOOOONG-release-name-minecraft name: LOOOOOOOONG-release-name-minecraft
@@ -93,7 +93,7 @@ metadata:
volume.alpha.kubernetes.io/storage-class: default volume.alpha.kubernetes.io/storage-class: default
labels: labels:
app: release-name-minecraft app: release-name-minecraft
chart: minecraft-1.0.0 chart: minecraft-1.0.1
heritage: Tiller heritage: Tiller
release: release-name release: release-name
name: LOOOOOOOONG-release-name-minecraft-datadir name: LOOOOOOOONG-release-name-minecraft-datadir

View File

@@ -31,24 +31,26 @@ namePrefix: blah-
configMapGenerator: configMapGenerator:
- name: bob - name: bob
literals: literals:
- fruit=apple - fruit=apple
- vegetable=broccoli - vegetable=broccoli
env: foo.env envs:
- foo.env
files: files:
- passphrase=phrase.dat - passphrase=phrase.dat
- forces.txt - forces.txt
- name: json - name: json
literals: literals:
- 'v2=[{"path": "var/druid/segment-cache"}]' - 'v2=[{"path": "var/druid/segment-cache"}]'
secretGenerator: secretGenerator:
- name: bob - name: bob
literals: literals:
- fruit=apple - fruit=apple
- vegetable=broccoli - vegetable=broccoli
env: foo.env envs:
- foo.env
files: files:
- passphrase=phrase.dat - passphrase=phrase.dat
- forces.txt - forces.txt
`) `)
th.WriteF("/app/foo.env", ` th.WriteF("/app/foo.env", `
MOUNTAIN=everest MOUNTAIN=everest
@@ -122,15 +124,15 @@ configMapGenerator:
- name: bob - name: bob
behavior: create behavior: create
literals: literals:
- bean=pinto - bean=pinto
- star=wolf-rayet - star=wolf-rayet
literals: literals:
- fruit=apple - fruit=apple
- vegetable=broccoli - vegetable=broccoli
files: files:
- forces.txt - forces.txt
files: files:
- nobles=nobility.txt - nobles=nobility.txt
`) `)
th.WriteF("/app/forces.txt", ` th.WriteF("/app/forces.txt", `
gravitational gravitational
@@ -177,7 +179,7 @@ configMapGenerator:
- name: com1 - name: com1
behavior: create behavior: create
literals: literals:
- from=base - from=base
`) `)
th.WriteK("/app/base2", ` th.WriteK("/app/base2", `
namePrefix: p2- namePrefix: p2-
@@ -185,7 +187,7 @@ configMapGenerator:
- name: com2 - name: com2
behavior: create behavior: create
literals: literals:
- from=base - from=base
`) `)
th.WriteK("/app/overlay/o1", ` th.WriteK("/app/overlay/o1", `
bases: bases:
@@ -194,7 +196,7 @@ configMapGenerator:
- name: com1 - name: com1
behavior: merge behavior: merge
literals: literals:
- from=overlay - from=overlay
`) `)
th.WriteK("/app/overlay/o2", ` th.WriteK("/app/overlay/o2", `
bases: bases:
@@ -203,7 +205,7 @@ configMapGenerator:
- name: com2 - name: com2
behavior: merge behavior: merge
literals: literals:
- from=overlay - from=overlay
`) `)
th.WriteK("/app/overlay", ` th.WriteK("/app/overlay", `
bases: bases:
@@ -213,8 +215,8 @@ configMapGenerator:
- name: com1 - name: com1
behavior: merge behavior: merge
literals: literals:
- foo=bar - foo=bar
- baz=qux - baz=qux
`) `)
m, err := th.MakeKustTarget().MakeCustomizedResMap() m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil { if err != nil {

View File

@@ -178,14 +178,14 @@ resources:
- deployment.yaml - deployment.yaml
- service.yaml - service.yaml
configMapGenerator: configMapGenerator:
- name: configmap-in-base - name: configmap-in-base
literals: literals:
- foo=bar - foo=bar
secretGenerator: secretGenerator:
- name: secret-in-base - name: secret-in-base
literals: literals:
- username=admin - username=admin
- password=somepw - password=somepw
`) `)
th.WriteF("/app/deployment.yaml", ` th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1beta2 apiVersion: apps/v1beta2
@@ -354,18 +354,18 @@ patchesStrategicMerge:
bases: bases:
- ../app - ../app
configMapGenerator: configMapGenerator:
- name: configmap-in-overlay - name: configmap-in-overlay
literals: literals:
- hello=world - hello=world
- name: configmap-in-base - name: configmap-in-base
behavior: replace behavior: replace
literals: literals:
- foo=override-bar - foo=override-bar
secretGenerator: secretGenerator:
- name: secret-in-base - name: secret-in-base
behavior: merge behavior: merge
literals: literals:
- proxy=haproxy - proxy=haproxy
`) `)
m, err := th.MakeKustTarget().MakeCustomizedResMap() m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil { if err != nil {

View File

@@ -17,14 +17,50 @@ limitations under the License.
package target_test package target_test
import ( import (
"path/filepath"
"strings"
"testing" "testing"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/kusttest" "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) { func TestGeneratorOptionsWithBases(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay") th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
th.WriteK("/app/base", ` th.WriteK("/app/base", `
@@ -77,47 +113,3 @@ metadata:
name: shouldNotHaveHash 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)
}
}

View File

@@ -144,7 +144,7 @@ func (kt *KustTarget) makeCustomizedResMap(
rm := ra.ResMap() rm := ra.ResMap()
pt := kt.tFactory.MakeInventoryTransformer( pt := kt.tFactory.MakeInventoryTransformer(
kt.kustomization.Inventory, kt.kustomization.Inventory, kt.ldr,
kt.kustomization.Namespace, kt.kustomization.Namespace,
garbagePolicy) garbagePolicy)
err = pt.Transform(rm) err = pt.Transform(rm)

View File

@@ -38,9 +38,9 @@ resources:
- deployment.yaml - deployment.yaml
- service.yaml - service.yaml
configMapGenerator: configMapGenerator:
- name: configmap-in-base - name: configmap-in-base
literals: literals:
- foo=bar - foo=bar
`) `)
th.WriteF("/app/base/deployment.yaml", ` th.WriteF("/app/base/deployment.yaml", `
apiVersion: apps/v1beta2 apiVersion: apps/v1beta2
@@ -93,9 +93,9 @@ patchesStrategicMerge:
bases: bases:
- ../../base - ../../base
configMapGenerator: configMapGenerator:
- name: configmap-in-overlay - name: configmap-in-overlay
literals: literals:
- hello=world - hello=world
`) `)
} }

View File

@@ -42,10 +42,10 @@ secretGenerator:
- name: the-non-default-namespace-secret - name: the-non-default-namespace-secret
namespace: non-default namespace: non-default
literals: literals:
- password.txt=verySecret - password.txt=verySecret
- name: the-secret - name: the-secret
literals: literals:
- password.txt=anotherSecret - password.txt=anotherSecret
`) `)
m, err := th.MakeKustTarget().MakeCustomizedResMap() m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil { if err != nil {

View File

@@ -10,7 +10,6 @@ import (
"testing" "testing"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/kunstruct"
kvplugin "sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/k8sdeps/transformer" "sigs.k8s.io/kustomize/k8sdeps/transformer"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/kusttest" "sigs.k8s.io/kustomize/pkg/kusttest"
@@ -19,7 +18,7 @@ import (
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/target" "sigs.k8s.io/kustomize/pkg/target"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/validators"
"sigs.k8s.io/kustomize/plugin" "sigs.k8s.io/kustomize/plugin"
) )
@@ -58,17 +57,15 @@ metadata:
t.Fatalf("err %v", err) 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 { if err != nil {
t.Fatalf("Err: %v", err) t.Fatalf("Err: %v", err)
} }
rf := resmap.NewFactory(resource.NewFactory( rf := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryWithGeneratorArgs( kunstruct.NewKunstructuredFactoryImpl()))
&types.GeneratorMetaArgs{
PluginConfig: kvplugin.ActivePluginConfig(),
})))
pl := plugins.NewLoader(kvplugin.ActivePluginConfig(), rf) pl := plugins.NewLoader(plugins.ActivePluginConfig(), rf)
tg, err := target.NewKustTarget(ldr, rf, transformer.NewFactoryImpl(), pl) tg, err := target.NewKustTarget(ldr, rf, transformer.NewFactoryImpl(), pl)
if err != nil { if err != nil {
t.Fatalf("err %v", err) t.Fatalf("err %v", err)

View File

@@ -4,6 +4,7 @@
package target_test package target_test
import ( import (
"strings"
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/kusttest" "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) { func TestSedTransformer(t *testing.T) {
tc := plugin.NewEnvForTest(t).Set() tc := plugin.NewEnvForTest(t).Set()
defer tc.Reset() defer tc.Reset()

View File

@@ -32,8 +32,8 @@ resources:
configMapGenerator: configMapGenerator:
- name: test-config-map - name: test-config-map
literals: literals:
- foo=bar - foo=bar
- baz=qux - baz=qux
vars: vars:
- name: CDB_PUBLIC_SVC - name: CDB_PUBLIC_SVC
objref: objref:

View File

@@ -111,7 +111,7 @@ commonLabels:
kind: StatefulSet kind: StatefulSet
- path: spec/volumeClaimTemplates/metadata/labels - path: spec/volumeClaimTemplates/metadata/labels
create: true create: false
group: apps group: apps
kind: StatefulSet kind: StatefulSet

View File

@@ -252,6 +252,12 @@ nameReference:
- path: spec/service/name - path: spec/service/name
kind: APIService kind: APIService
group: apiregistration.k8s.io 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 - kind: Role
group: rbac.authorization.k8s.io group: rbac.authorization.k8s.io

View File

@@ -1,28 +1,14 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 config package config
import ( import (
"reflect" "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" "testing"
"sigs.k8s.io/kustomize/internal/loadertest"
"sigs.k8s.io/kustomize/pkg/gvk"
) )
func TestMakeDefaultConfig(t *testing.T) { func TestMakeDefaultConfig(t *testing.T) {
@@ -30,20 +16,15 @@ func TestMakeDefaultConfig(t *testing.T) {
_ = MakeDefaultConfig() _ = 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) { func TestFromFiles(t *testing.T) {
path := "/transformerconfig/test/config.yaml"
ldr := makeTestLoader(path, ` ldr := loadertest.NewFakeLoader("/app")
ldr.AddFile("/app/config.yaml", []byte(`
namePrefix: namePrefix:
- path: nameprefix/path - path: nameprefix/path
kind: SomeKind kind: SomeKind
`) `))
tcfg, err := NewFactory(ldr).FromFiles([]string{"transformerconfig/test/config.yaml"}) tcfg, err := NewFactory(ldr).FromFiles([]string{"/app/config.yaml"})
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }

View File

@@ -222,15 +222,6 @@ type GeneratorArgs struct {
// DataSources for the generator. // DataSources for the generator.
DataSources `json:",inline,omitempty" yaml:",inline,omitempty"` 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. // PluginConfig holds plugin configuration.
@@ -241,9 +232,8 @@ type PluginConfig struct {
// further categorizing plugins. // further categorizing plugins.
DirectoryPath string DirectoryPath string
// GoEnabled is true if goplugins are enabled. // Enabled is true if plugins are enabled.
// See https://golang.org/pkg/plugin Enabled bool
GoEnabled bool
} }
// ConfigMapArgs contains the metadata of how to generate a configmap. // ConfigMapArgs contains the metadata of how to generate a configmap.
@@ -252,6 +242,12 @@ type ConfigMapArgs struct {
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"` 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. // SecretArgs contains the metadata of how to generate a secret.
type SecretArgs struct { type SecretArgs struct {
// GeneratorArgs for the secret. // GeneratorArgs for the secret.

View File

@@ -1,18 +1,5 @@
/* // Copyright 2019 The Kubernetes Authors.
Copyright 2018 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 validators defines a FakeValidator that can be used in tests // Package validators defines a FakeValidator that can be used in tests
package validators package validators
@@ -48,6 +35,16 @@ func MakeFakeValidator() *FakeValidator {
return &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 // MakeAnnotationValidator returns a nil function
func (v *FakeValidator) MakeAnnotationValidator() func(map[string]string) error { func (v *FakeValidator) MakeAnnotationValidator() func(map[string]string) error {
return nil return nil

View File

@@ -24,6 +24,10 @@
# Example execution: # Example execution:
# ./plugin/someteam.example.com/v1/ChartInflator configFile.yaml # ./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 set -e
# Yaml parsing is a ridiculous thing to do in bash, # Yaml parsing is a ridiculous thing to do in bash,

View File

@@ -42,7 +42,7 @@ kind: Secret
metadata: metadata:
labels: labels:
app: release-name-minecraft app: release-name-minecraft
chart: minecraft-1.0.0 chart: minecraft-1.0.1
heritage: Tiller heritage: Tiller
release: release-name release: release-name
name: release-name-minecraft name: release-name-minecraft
@@ -53,7 +53,7 @@ kind: Service
metadata: metadata:
labels: labels:
app: release-name-minecraft app: release-name-minecraft
chart: minecraft-1.0.0 chart: minecraft-1.0.1
heritage: Tiller heritage: Tiller
release: release-name release: release-name
name: release-name-minecraft name: release-name-minecraft
@@ -74,7 +74,7 @@ metadata:
volume.alpha.kubernetes.io/storage-class: default volume.alpha.kubernetes.io/storage-class: default
labels: labels:
app: release-name-minecraft app: release-name-minecraft
chart: minecraft-1.0.0 chart: minecraft-1.0.1
heritage: Tiller heritage: Tiller
release: release-name release: release-name
name: release-name-minecraft-datadir name: release-name-minecraft-datadir

View File

@@ -34,6 +34,7 @@ var database = map[string]string{
func (p *plugin) Config( func (p *plugin) Config(
ldr ifc.Loader, rf *resmap.Factory, c []byte) error { ldr ifc.Loader, rf *resmap.Factory, c []byte) error {
p.rf = rf p.rf = rf
p.ldr = ldr
return yaml.Unmarshal(c, p) return yaml.Unmarshal(c, p)
} }