Merge branch 'master' into builtins

This commit is contained in:
Seth Pollack
2019-03-17 17:01:06 -04:00
committed by GitHub
26 changed files with 683 additions and 530 deletions

View File

@@ -1,37 +1,46 @@
# Transformer Configurations # Transformer Configurations
Kustomize computes the resources by applying a series of transformers: Kustomize creates new resources by applying a series of transformations to an original
- namespace transformer set of resources. Kustomize provides the following default transformers:
- prefix/suffix transformer
- label transformer
- annotation transformer
- name reference transformer
- variable reference transformer
Each transformer takes a list of resources and modifies certain fields. The modification is based on the transformer's rule. - namespace
The fields to update is the transformer's configuration, which is a list of filedspec that can be represented in YAML format. - prefix/suffix
- label
- annotation
- name reference
- variable reference
## fieldSpec A `fieldSpec` list, in a transformer's configuration, determines which resource types and which fields
FieldSpec is a type to represent a path to a field in one kind of resources. It has following format within those types the transformer can modify.
```
## FieldSpec
FieldSpec is a type that represents a path to a field in one kind of resource.
```yaml
group: some-group group: some-group
version: some-version version: some-version
kind: some-kind kind: some-kind
path: path/to/the/field path: path/to/the/field
create: false create: false
``` ```
If `create` is set to true, it indicates the transformer to create the path if it is not found in the resources. This is most useful for label and annotation transformers, where the path for labels or annotations may not be set before the transformation.
## prefix/suffix transformer If `create` is set to `true`, the transformer creates the path to the field in the resource if the path is not already found. This is most useful for label and annotation transformers, where the path for labels or annotations may not be set before the transformation.
Name prefix suffix transformer adds prefix and suffix to the `metadata/name` field for all resources with following configuration:
``` ## Prefix/suffix transformer
The prefix/suffix transformer adds a prefix/suffix to the `metadata/name` field for all resources. Here is the default prefix transformer configuration:
```yaml
namePrefix: namePrefix:
- path: metadata/name - path: metadata/name
``` ```
## label transformer ## Label transformer
Label transformer adds labels to `metadata/labels` field for all resources. It also adds labels to `spec/selector` field in all Service and to `spec/selector/matchLabels` field in all Deployment.
``` The label transformer adds labels to the `metadata/labels` field for all resources. It also adds labels to the `spec/selector` field in all Service resources as well as the `spec/selector/matchLabels` field in all Deployment resources.
```yaml
commonLabels: commonLabels:
- path: metadata/labels - path: metadata/labels
create: true create: true
@@ -44,15 +53,16 @@ commonLabels:
- path: spec/selector/matchLabels - path: spec/selector/matchLabels
create: true create: true
kind: Deployment kind: Deployment
(etc.)
``` ```
## name reference transformer ## Name reference transformer
Name reference transformer's configuration is different from all other transformers. It contains a list of namebackreferences, which represented all the possible fields that a type could be used as a reference in other types of resources. A namebackreference contains a type such as ConfigMap as well as a list of FieldSpecs where ConfigMap is referenced. Here is an example.
``` Name reference transformer's configuration is different from all other transformers. It contains a list of `nameReferences`, which represent all of the possible fields that a type could be used as a reference in other types of resources. A `nameReference` contains a type such as ConfigMap as well as a list of `fieldSpecs` where ConfigMap is referenced in other resources. Here is an example:
```yaml
kind: ConfigMap kind: ConfigMap
version: v1 version: v1
FieldSpecs: fieldSpecs:
- kind: Pod - kind: Pod
version: v1 version: v1
path: spec/volumes/configMap/name path: spec/volumes/configMap/name
@@ -60,10 +70,11 @@ FieldSpecs:
path: spec/template/spec/volumes/configMap/name path: spec/template/spec/volumes/configMap/name
- kind: Job - kind: Job
path: spec/template/spec/volumes/configMap/name path: spec/template/spec/volumes/configMap/name
(etc.)
```
Name reference transformer configuration contains a list of such namebackreferences for ConfigMap, Secret, Service, Role, ServiceAccount and so on.
``` ```
Name reference transformer's configuration contains a list of `nameReferences` for resources such as ConfigMap, Secret, Service, Role, and ServiceAccount. Here is an example configuration:
```yaml
nameReference: nameReference:
- kind: ConfigMap - kind: ConfigMap
version: v1 version: v1
@@ -74,7 +85,7 @@ nameReference:
- path: spec/containers/env/valueFrom/configMapKeyRef/name - path: spec/containers/env/valueFrom/configMapKeyRef/name
version: v1 version: v1
kind: Pod kind: Pod
(etc.) # ...
- kind: Secret - kind: Secret
version: v1 version: v1
fieldSpecs: fieldSpecs:
@@ -84,12 +95,12 @@ nameReference:
- path: spec/containers/env/valueFrom/secretKeyRef/name - path: spec/containers/env/valueFrom/secretKeyRef/name
version: v1 version: v1
kind: Pod kind: Pod
(etc.)
``` ```
## customizing transformer configurations ## Customizing transformer configurations
Kustomize has a default set of transformer configurations. You can save the default transformer configurations to a local directory by calling `kustomize config save -d`, and modify and use these configurations. Kustomize also supports adding new transformer configurations to kustomization.yaml. This tutorial shows how to customize those configurations to:
Kustomize has a default set of configurations. They can be saved to local directory through `kustomize config save -d`. Kustomize allows modifying those configuration files and using them in kustomization.yaml file. This tutorial shows how to customize those configurations to
- [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

View File

@@ -21,8 +21,7 @@ import (
"fmt" "fmt"
"unicode/utf8" "unicode/utf8"
corev1 "k8s.io/api/core/v1" "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "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"
@@ -40,8 +39,8 @@ func NewFactory(
} }
func makeFreshConfigMap( func makeFreshConfigMap(
args *types.ConfigMapArgs) *corev1.ConfigMap { args *types.ConfigMapArgs) *v1.ConfigMap {
cm := &corev1.ConfigMap{} cm := &v1.ConfigMap{}
cm.APIVersion = "v1" cm.APIVersion = "v1"
cm.Kind = "ConfigMap" cm.Kind = "ConfigMap"
cm.Name = args.Name cm.Name = args.Name
@@ -52,7 +51,7 @@ 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) (*corev1.ConfigMap, error) { args *types.ConfigMapArgs) (*v1.ConfigMap, error) {
all, err := f.loadKvPairs(args.GeneratorArgs) all, err := f.loadKvPairs(args.GeneratorArgs)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -1,34 +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 k8sdeps provides kustomize factory with k8s dependencies
package k8sdeps
import (
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/k8sdeps/transformer"
"sigs.k8s.io/kustomize/k8sdeps/validator"
"sigs.k8s.io/kustomize/pkg/factory"
)
// NewFactory creates an instance of KustFactory using k8sdeps factories
func NewFactory() *factory.KustFactory {
return factory.NewKustFactory(
kunstruct.NewKunstructuredFactoryImpl(),
validator.NewKustValidator(),
transformer.NewFactoryImpl(),
)
}

View File

@@ -32,13 +32,21 @@ import (
// 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 &KunstructuredFactoryImpl{} return NewKunstructuredFactoryWithGeneratorArgs(
&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.
@@ -82,7 +90,10 @@ func (kf *KunstructuredFactoryImpl) MakeConfigMap(
ldr ifc.Loader, ldr ifc.Loader,
options *types.GeneratorOptions, options *types.GeneratorOptions,
args *types.ConfigMapArgs) (ifc.Kunstructured, error) { args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory(ldr, options, plugin.NewRegistry(ldr)).MakeConfigMap(args) o, err := configmapandsecret.NewFactory(
ldr, options,
plugin.NewConfiguredRegistry(
ldr, &kf.generatorMetaArgs.PluginConfig)).MakeConfigMap(args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -94,7 +105,10 @@ func (kf *KunstructuredFactoryImpl) MakeSecret(
ldr ifc.Loader, ldr ifc.Loader,
options *types.GeneratorOptions, options *types.GeneratorOptions,
args *types.SecretArgs) (ifc.Kunstructured, error) { args *types.SecretArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory(ldr, options, plugin.NewRegistry(ldr)).MakeSecret(args) o, err := configmapandsecret.NewFactory(
ldr, options,
plugin.NewConfiguredRegistry(
ldr, &kf.generatorMetaArgs.PluginConfig)).MakeSecret(args)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -18,23 +18,45 @@ package plugin
import ( import (
"fmt" "fmt"
"os" "path/filepath"
"plugin" "plugin"
"sigs.k8s.io/kustomize/pkg/types"
) )
var _ Factory = &goFactory{} var _ Factory = &goFactory{}
const ( const (
dir = "$HOME/.config/kustomize/plugins/kvsource" kvSourcesDir = "kvSources"
EnableGoPluginsFlagName = "enable_alpha_goplugins_accept_panic_risk"
EnableGoPluginsFlagHelp = `
Warning: 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() *goFactory { func newGoFactory(c *types.PluginConfig) *goFactory {
return &goFactory{ return &goFactory{
config: c,
plugins: make(map[string]KVSource), plugins: make(map[string]KVSource),
} }
} }
type goFactory struct { type goFactory struct {
config *types.PluginConfig
plugins map[string]KVSource plugins map[string]KVSource
} }
@@ -43,7 +65,19 @@ func (p *goFactory) load(name string) (KVSource, error) {
return plug, nil return plug, nil
} }
goPlugin, err := plugin.Open(fmt.Sprintf("%s/kustomize-%s.so", os.ExpandEnv(dir), name)) 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 { if err != nil {
return nil, err return nil, err
} }

View File

@@ -18,8 +18,10 @@ package plugin
import ( import (
"fmt" "fmt"
"path/filepath"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/types"
) )
// Registry holds all the plugin factories. // Registry holds all the plugin factories.
@@ -28,17 +30,36 @@ type Registry struct {
ldr ifc.Loader ldr ifc.Loader
} }
// NewRegistry returns a new Registry loaded with all the factories. const (
func NewRegistry(ldr ifc.Loader) Registry { PluginsDir = "plugins"
)
func DefaultPluginConfig() types.PluginConfig {
return types.PluginConfig{
GoEnabled: false,
DirectoryPath: filepath.Join(
pgmconfig.ConfigRoot(), PluginsDir),
}
}
// 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{ return Registry{
ldr: ldr, ldr: ldr,
factories: map[string]Factory{ factories: map[string]Factory{
"go": newGoFactory(), "go": newGoFactory(pc),
"builtin": newBuiltinFactory(ldr), "builtin": 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, // Load returns a plugin by type and name,
func (r *Registry) Load(pluginType, name string) (KVSource, error) { func (r *Registry) Load(pluginType, name string) (KVSource, error) {
factory, exists := r.factories[pluginType] factory, exists := r.factories[pluginType]

View File

@@ -19,12 +19,11 @@ package main
import ( import (
"os" "os"
"sigs.k8s.io/kustomize/k8sdeps"
"sigs.k8s.io/kustomize/pkg/commands" "sigs.k8s.io/kustomize/pkg/commands"
) )
func main() { func main() {
if err := commands.NewDefaultCommand(k8sdeps.NewFactory()).Execute(); err != nil { if err := commands.NewDefaultCommand().Execute(); err != nil {
os.Exit(1) os.Exit(1)
} }
os.Exit(0) os.Exit(0)

View File

@@ -21,10 +21,10 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/ifc/transformer" "sigs.k8s.io/kustomize/pkg/ifc/transformer"
"sigs.k8s.io/kustomize/pkg/loader" "sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/target" "sigs.k8s.io/kustomize/pkg/target"
) )
@@ -67,7 +67,7 @@ func NewCmdBuild(
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "build [path]", Use: "build [path]",
Short: "Print current configuration per contents of " + constants.KustomizationFileNames[0], Short: "Print current configuration per contents of " + pgmconfig.KustomizationFileNames[0],
Example: examples, Example: examples,
SilenceUsage: true, SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@@ -88,7 +88,7 @@ func NewCmdBuild(
// Validate validates build command. // Validate validates build command.
func (o *Options) Validate(args []string) error { func (o *Options) Validate(args []string) error {
if len(args) > 1 { if len(args) > 1 {
return errors.New("specify one path to " + constants.KustomizationFileNames[0]) return errors.New("specify one path to " + pgmconfig.KustomizationFileNames[0])
} }
if len(args) == 0 { if len(args) == 0 {
o.kustomizationPath = "./" o.kustomizationPath = "./"

View File

@@ -19,7 +19,7 @@ package build
import ( import (
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/pgmconfig"
) )
func TestNewOptionsToSilenceCodeInspectionError(t *testing.T) { func TestNewOptionsToSilenceCodeInspectionError(t *testing.T) {
@@ -39,7 +39,7 @@ func TestBuildValidate(t *testing.T) {
{"file", []string{"beans"}, "beans", ""}, {"file", []string{"beans"}, "beans", ""},
{"path", []string{"a/b/c"}, "a/b/c", ""}, {"path", []string{"a/b/c"}, "a/b/c", ""},
{"path", []string{"too", "many"}, {"path", []string{"too", "many"},
"", "specify one path to " + constants.KustomizationFileNames[0]}, "", "specify one path to " + pgmconfig.KustomizationFileNames[0]},
} }
for _, mycase := range cases { for _, mycase := range cases {
opts := Options{} opts := Options{}

View File

@@ -20,35 +20,57 @@ package commands
import ( import (
"flag" "flag"
"os" "os"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/k8sdeps/transformer"
"sigs.k8s.io/kustomize/k8sdeps/validator"
"sigs.k8s.io/kustomize/pkg/commands/build" "sigs.k8s.io/kustomize/pkg/commands/build"
"sigs.k8s.io/kustomize/pkg/commands/edit" "sigs.k8s.io/kustomize/pkg/commands/edit"
"sigs.k8s.io/kustomize/pkg/commands/misc" "sigs.k8s.io/kustomize/pkg/commands/misc"
"sigs.k8s.io/kustomize/pkg/factory"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
"sigs.k8s.io/kustomize/pkg/types"
) )
// NewDefaultCommand returns the default (aka root) command for kustomize command. // NewDefaultCommand returns the default (aka root) command for kustomize command.
func NewDefaultCommand(f *factory.KustFactory) *cobra.Command { func NewDefaultCommand() *cobra.Command {
fsys := fs.MakeRealFS() fSys := fs.MakeRealFS()
stdOut := os.Stdout stdOut := os.Stdout
c := &cobra.Command{ c := &cobra.Command{
Use: "kustomize", Use: pgmconfig.PgmName,
Short: "kustomize manages declarative configuration of Kubernetes", Short: "Manages declarative configuration of Kubernetes",
Long: ` Long: `
kustomize manages declarative configuration of Kubernetes. Manages declarative configuration of Kubernetes.
See https://sigs.k8s.io/kustomize See https://sigs.k8s.io/kustomize
`, `,
} }
// Configuration for ConfigMap and Secret generators.
genMetaArgs := types.GeneratorMetaArgs{
PluginConfig: plugin.DefaultPluginConfig(),
}
c.Flags().BoolVar(
&genMetaArgs.PluginConfig.GoEnabled,
plugin.EnableGoPluginsFlagName,
false, plugin.EnableGoPluginsFlagHelp)
// Not advertising this alpha feature.
c.Flags().MarkHidden(plugin.EnableGoPluginsFlagName)
uf := kunstruct.NewKunstructuredFactoryWithGeneratorArgs(&genMetaArgs)
c.AddCommand( c.AddCommand(
// TODO: Make consistent API for newCmd* functions. build.NewCmdBuild(
build.NewCmdBuild(stdOut, fsys, f.ResmapF, f.TransformerF), stdOut, fSys,
edit.NewCmdEdit(fsys, f.ValidatorF, f.UnstructF), resmap.NewFactory(resource.NewFactory(uf)),
misc.NewCmdConfig(fsys), transformer.NewFactoryImpl()),
edit.NewCmdEdit(fSys, validator.NewKustValidator(), uf),
misc.NewCmdConfig(fSys),
misc.NewCmdVersion(stdOut), misc.NewCmdVersion(stdOut),
) )
c.PersistentFlags().AddGoFlagSet(flag.CommandLine) c.PersistentFlags().AddGoFlagSet(flag.CommandLine)

View File

@@ -22,8 +22,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/pkg/commands/kustfile" "sigs.k8s.io/kustomize/pkg/commands/kustfile"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
) )
@@ -59,7 +59,7 @@ func newCmdAddAnnotation(fSys fs.FileSystem, v func(map[string]string) error) *c
o.mapValidator = v o.mapValidator = v
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "annotation", Use: "annotation",
Short: "Adds one or more commonAnnotations to " + constants.KustomizationFileNames[0], Short: "Adds one or more commonAnnotations to " + pgmconfig.KustomizationFileNames[0],
Example: ` Example: `
add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}`, add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@@ -76,7 +76,7 @@ func newCmdAddLabel(fSys fs.FileSystem, v func(map[string]string) error) *cobra.
o.mapValidator = v o.mapValidator = v
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "label", Use: "label",
Short: "Adds one or more commonLabels to " + constants.KustomizationFileNames[0], Short: "Adds one or more commonLabels to " + pgmconfig.KustomizationFileNames[0],
Example: ` Example: `
add label {labelKey1:labelValue1},{labelKey2:labelValue2}`, add label {labelKey1:labelValue1},{labelKey2:labelValue2}`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {

View File

@@ -27,8 +27,8 @@ import (
"strings" "strings"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
) )
@@ -129,7 +129,7 @@ func NewKustomizationFile(fSys fs.FileSystem) (*kustomizationFile, error) { // n
func (mf *kustomizationFile) validate() error { func (mf *kustomizationFile) validate() error {
match := 0 match := 0
var path []string var path []string
for _, kfilename := range constants.KustomizationFileNames { for _, kfilename := range pgmconfig.KustomizationFileNames {
if mf.fSys.Exists(kfilename) { if mf.fSys.Exists(kfilename) {
match += 1 match += 1
path = append(path, kfilename) path = append(path, kfilename)
@@ -138,7 +138,7 @@ func (mf *kustomizationFile) validate() error {
switch match { switch match {
case 0: case 0:
return fmt.Errorf("Missing kustomization file '%s'.\n", constants.KustomizationFileNames[0]) return fmt.Errorf("Missing kustomization file '%s'.\n", pgmconfig.KustomizationFileNames[0])
case 1: case 1:
mf.path = path[0] mf.path = path[0]
default: default:

View File

@@ -21,8 +21,8 @@ import (
"strings" "strings"
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/types" "sigs.k8s.io/kustomize/pkg/types"
) )
@@ -112,12 +112,12 @@ configMapGenerator:
name: my-configmap name: my-configmap
` `
fakeFS := fs.MakeFakeFS() fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(constants.KustomizationFileNames[1], []byte(kcontent)) fakeFS.WriteFile(pgmconfig.KustomizationFileNames[1], []byte(kcontent))
k, err := NewKustomizationFile(fakeFS) k, err := NewKustomizationFile(fakeFS)
if err != nil { if err != nil {
t.Fatalf("Unexpected Error: %v", err) t.Fatalf("Unexpected Error: %v", err)
} }
if k.path != constants.KustomizationFileNames[1] { if k.path != pgmconfig.KustomizationFileNames[1] {
t.Fatalf("Load incorrect file path %s", k.path) t.Fatalf("Load incorrect file path %s", k.path)
} }
} }

View File

@@ -1,39 +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 factory provides factories for kustomize.
package factory
import (
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/ifc/transformer"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
)
// KustFactory provides different factories for kustomize
type KustFactory struct {
ResmapF *resmap.Factory
TransformerF transformer.Factory
ValidatorF ifc.Validator
UnstructF ifc.KunstructuredFactory
}
// NewKustFactory creats a KustFactory instance
func NewKustFactory(u ifc.KunstructuredFactory, v ifc.Validator, t transformer.Factory) *KustFactory {
return &KustFactory{
ResmapF: resmap.NewFactory(resource.NewFactory(u)),
TransformerF: t,
ValidatorF: v,
UnstructF: u,
}
}

View File

@@ -22,7 +22,7 @@ import (
"sort" "sort"
"strings" "strings"
"sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/pgmconfig"
) )
var _ FileSystem = &fakeFs{} var _ FileSystem = &fakeFs{}
@@ -158,7 +158,7 @@ func (fs *fakeFs) ReadFile(name string) ([]byte, error) {
} }
func (fs *fakeFs) ReadTestKustomization() ([]byte, error) { func (fs *fakeFs) ReadTestKustomization() ([]byte, error) {
return fs.ReadFile(constants.KustomizationFileNames[0]) return fs.ReadFile(pgmconfig.KustomizationFileNames[0])
} }
// WriteFile always succeeds and does nothing. // WriteFile always succeeds and does nothing.
@@ -176,7 +176,7 @@ func (fs *fakeFs) WriteTestKustomization() {
// WriteTestKustomizationWith writes a standard test file. // WriteTestKustomizationWith writes a standard test file.
func (fs *fakeFs) WriteTestKustomizationWith(bytes []byte) { func (fs *fakeFs) WriteTestKustomizationWith(bytes []byte) {
fs.WriteFile(constants.KustomizationFileNames[0], bytes) fs.WriteFile(pgmconfig.KustomizationFileNames[0], bytes)
} }
func (fs *fakeFs) pathMatch(path, pattern string) bool { func (fs *fakeFs) pathMatch(path, pattern string) bool {

View File

@@ -25,8 +25,8 @@ import (
"strings" "strings"
"testing" "testing"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/git" "sigs.k8s.io/kustomize/pkg/git"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
@@ -341,7 +341,7 @@ func TestNewLoaderAtGitClone(t *testing.T) {
fSys.MkdirAll(coRoot) fSys.MkdirAll(coRoot)
fSys.MkdirAll(coRoot + "/" + pathInRepo) fSys.MkdirAll(coRoot + "/" + pathInRepo)
fSys.WriteFile( fSys.WriteFile(
coRoot+"/"+pathInRepo+"/"+constants.KustomizationFileNames[0], coRoot+"/"+pathInRepo+"/"+pgmconfig.KustomizationFileNames[0],
[]byte(` []byte(`
whatever whatever
`)) `))

54
pkg/pgmconfig/config.go Normal file
View File

@@ -0,0 +1,54 @@
/*
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 commands holds the CLI glue mapping textual commands/args to method calls.
package pgmconfig
import (
"os"
"path/filepath"
"runtime"
)
const (
XDG_CONFIG_HOME = "XDG_CONFIG_HOME"
defaultConfigSubdir = ".config"
)
// Use https://github.com/kirsle/configdir instead?
func ConfigRoot() string {
dir := os.Getenv(XDG_CONFIG_HOME)
if len(dir) == 0 {
dir = filepath.Join(
homeDir(), defaultConfigSubdir)
}
return filepath.Join(dir, PgmName)
}
func homeDir() string {
home := os.Getenv(homeEnv())
if len(home) > 0 {
return home
}
return "~"
}
func homeEnv() string {
if runtime.GOOS == "windows" {
return "USERPROFILE"
}
return "HOME"
}

View File

@@ -0,0 +1,56 @@
/*
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 pgmconfig
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestConfigDirNoXdg(t *testing.T) {
xdg, isSet := os.LookupEnv(XDG_CONFIG_HOME)
if isSet {
os.Unsetenv(XDG_CONFIG_HOME)
}
s := ConfigRoot()
if isSet {
os.Setenv(XDG_CONFIG_HOME, xdg)
}
if !strings.HasSuffix(
s,
rootedPath(defaultConfigSubdir, PgmName)) {
t.Fatalf("unexpected config dir: %s", s)
}
}
func rootedPath(elem ...string) string {
return string(filepath.Separator) + filepath.Join(elem...)
}
func TestConfigDirWithXdg(t *testing.T) {
xdg, isSet := os.LookupEnv(XDG_CONFIG_HOME)
os.Setenv(XDG_CONFIG_HOME, rootedPath("blah"))
s := ConfigRoot()
if isSet {
os.Setenv(XDG_CONFIG_HOME, xdg)
}
if s != rootedPath("blah", PgmName) {
t.Fatalf("unexpected config dir: %s", s)
}
}

View File

@@ -15,14 +15,18 @@ limitations under the License.
*/ */
// Package constants holds global constants for the kustomize tool. // Package constants holds global constants for the kustomize tool.
package constants package pgmconfig
// KustomizationFileNames is a list of filenames that can be recognized and consumbed // KustomizationFileNames is a list of filenames
// by Kustomize. // that kustomize recognizes.
// In each directory, Kustomize searches for file with the name in this list. // To avoid ambiguity, a directory cannot contain
// Only one match is allowed. // more than one match to this list.
var KustomizationFileNames = []string{ var KustomizationFileNames = []string{
"kustomization.yaml", "kustomization.yaml",
"kustomization.yml", "kustomization.yml",
"Kustomization", "Kustomization",
} }
const (
PgmName = "kustomize"
)

View File

@@ -14,6 +14,9 @@ limitations under the License.
package target_test package target_test
import ( import (
"path/filepath"
"sigs.k8s.io/kustomize/pkg/types"
"strings"
"testing" "testing"
) )
@@ -69,3 +72,47 @@ metadata:
name: shouldNotHaveHash name: shouldNotHaveHash
`) `)
} }
func TestGoPluginNotEnabled(t *testing.T) {
th := 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 := NewKustTestHarnessWithPluginConfig(
t, "/app", types.PluginConfig{GoEnabled: true})
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

@@ -25,11 +25,11 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/pkg/errors" "github.com/pkg/errors"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/ifc/transformer" "sigs.k8s.io/kustomize/pkg/ifc/transformer"
interror "sigs.k8s.io/kustomize/pkg/internal/error" interror "sigs.k8s.io/kustomize/pkg/internal/error"
patchtransformer "sigs.k8s.io/kustomize/pkg/patch/transformer" patchtransformer "sigs.k8s.io/kustomize/pkg/patch/transformer"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"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/transformers" "sigs.k8s.io/kustomize/pkg/transformers"
@@ -89,7 +89,7 @@ func commaOr(q []string) string {
func loadKustFile(ldr ifc.Loader) ([]byte, error) { func loadKustFile(ldr ifc.Loader) ([]byte, error) {
var content []byte var content []byte
match := 0 match := 0
for _, kf := range constants.KustomizationFileNames { for _, kf := range pgmconfig.KustomizationFileNames {
c, err := ldr.Load(kf) c, err := ldr.Load(kf)
if err == nil { if err == nil {
match += 1 match += 1
@@ -100,7 +100,7 @@ func loadKustFile(ldr ifc.Loader) ([]byte, error) {
case 0: case 0:
return nil, fmt.Errorf( return nil, fmt.Errorf(
"unable to find one of %v in directory '%s'", "unable to find one of %v in directory '%s'",
commaOr(quoted(constants.KustomizationFileNames)), ldr.Root()) commaOr(quoted(pgmconfig.KustomizationFileNames)), ldr.Root())
case 1: case 1:
return content, nil return content, nil
default: default:

View File

@@ -21,13 +21,14 @@ package target_test
import ( import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"strings" "strings"
"testing" "testing"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/k8sdeps/transformer" "sigs.k8s.io/kustomize/k8sdeps/transformer"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/internal/loadertest" "sigs.k8s.io/kustomize/pkg/internal/loadertest"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"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"
@@ -42,10 +43,18 @@ type KustTestHarness struct {
} }
func NewKustTestHarness(t *testing.T, path string) *KustTestHarness { func NewKustTestHarness(t *testing.T, path string) *KustTestHarness {
return NewKustTestHarnessWithPluginConfig(
t, path, plugin.DefaultPluginConfig())
}
func NewKustTestHarnessWithPluginConfig(
t *testing.T, path string,
config types.PluginConfig) *KustTestHarness {
return &KustTestHarness{ return &KustTestHarness{
t: t, t: t,
rf: resmap.NewFactory(resource.NewFactory( rf: resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())), kunstruct.NewKunstructuredFactoryWithGeneratorArgs(
&types.GeneratorMetaArgs{PluginConfig: config}))),
ldr: loadertest.NewFakeLoader(path)} ldr: loadertest.NewFakeLoader(path)}
} }
@@ -66,7 +75,7 @@ func (th *KustTestHarness) writeF(dir string, content string) {
} }
func (th *KustTestHarness) writeK(dir string, content string) { func (th *KustTestHarness) writeK(dir string, content string) {
th.writeF(filepath.Join(dir, constants.KustomizationFileNames[0]), ` th.writeF(filepath.Join(dir, pgmconfig.KustomizationFileNames[0]), `
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
`+content) `+content)

View File

@@ -0,0 +1,170 @@
/*
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"
)
func makeTransfomersImageBase(th *KustTestHarness) {
th.writeK("/app/base", `
resources:
- deploy1.yaml
- random.yaml
images:
- name: nginx
newTag: v2
- name: my-nginx
newTag: previous
- name: myprivaterepohostname:1234/my/image
newTag: v1.0.1
- name: foobar
digest: sha256:24a0c4b4
- name: alpine
newName: myprivaterepohostname:1234/my/cool-alpine
- name: gcr.io:8080/my-project/my-cool-app
newName: my-cool-app
- name: postgres
newName: my-postgres
newTag: v3
- name: docker
newName: my-docker
digest: sha256:25a0d4b4
`)
th.writeF("/app/base/deploy1.yaml", `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
initContainers:
- name: nginx2
image: my-nginx:1.8.0
- name: init-alpine
image: alpine:1.8.0
containers:
- name: ngnix
image: nginx:1.7.9
- name: repliaced-with-digest
image: foobar:1
- name: postgresdb
image: postgres:1.8.0
`)
th.writeF("/app/base/random.yaml", `
kind: randomKind
metadata:
name: random
spec:
template:
spec:
containers:
- name: ngnix1
image: nginx
spec2:
template:
spec:
containers:
- name: nginx3
image: nginx:v1
- name: nginx4
image: my-nginx:latest
spec3:
template:
spec:
initContainers:
- name: postgresdb
image: postgres:alpine-9
- name: init-docker
image: docker:17-git
- name: myImage
image: myprivaterepohostname:1234/my/image:latest
- name: myImage2
image: myprivaterepohostname:1234/my/image
- name: my-app
image: my-app-image:v1
- name: my-cool-app
image: gcr.io:8080/my-project/my-cool-app:latest
`)
}
func TestTransfomersImageDefaultConfig(t *testing.T) {
th := NewKustTestHarness(t, "/app/base")
makeTransfomersImageBase(th)
m, err := th.makeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.assertActualEqualsExpected(m, `
apiVersion: v1
group: apps
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx:v2
name: ngnix
- image: foobar@sha256:24a0c4b4
name: repliaced-with-digest
- image: my-postgres:v3
name: postgresdb
initContainers:
- image: my-nginx:previous
name: nginx2
- image: myprivaterepohostname:1234/my/cool-alpine:1.8.0
name: init-alpine
---
kind: randomKind
metadata:
name: random
spec:
template:
spec:
containers:
- image: nginx:v2
name: ngnix1
spec2:
template:
spec:
containers:
- image: nginx:v2
name: nginx3
- image: my-nginx:previous
name: nginx4
spec3:
template:
spec:
initContainers:
- image: my-postgres:v3
name: postgresdb
- image: my-docker@sha256:25a0d4b4
name: init-docker
- image: myprivaterepohostname:1234/my/image:v1.0.1
name: myImage
- image: myprivaterepohostname:1234/my/image:v1.0.1
name: myImage2
- image: my-app-image:v1
name: my-app
- image: my-cool-app:latest
name: my-cool-app
`)
}

View File

@@ -19,98 +19,77 @@ package defaultconfig
const ( const (
varReferenceFieldSpecs = ` varReferenceFieldSpecs = `
varReference: varReference:
- path: spec/template/spec/initContainers/command - path: spec/jobTemplate/spec/template/spec/containers/args
kind: StatefulSet kind: CronJob
- path: spec/template/spec/containers/command
kind: StatefulSet
- path: spec/template/spec/initContainers/command
kind: Deployment
- path: spec/template/spec/containers/command
kind: Deployment
- path: spec/template/spec/initContainers/command
kind: DaemonSet
- path: spec/template/spec/containers/command
kind: DaemonSet
- path: spec/template/spec/containers/command
kind: Job
- path: spec/jobTemplate/spec/template/spec/containers/command - path: spec/jobTemplate/spec/template/spec/containers/command
kind: CronJob kind: CronJob
- path: spec/template/spec/initContainers/args
kind: StatefulSet
- path: spec/template/spec/containers/args
kind: StatefulSet
- path: spec/template/spec/initContainers/args
kind: Deployment
- path: spec/template/spec/containers/args
kind: Deployment
- path: spec/template/spec/initContainers/args
kind: DaemonSet
- path: spec/template/spec/containers/args
kind: DaemonSet
- path: spec/template/spec/containers/args
kind: Job
- path: spec/jobTemplate/spec/template/spec/containers/args
kind: CronJob
- path: spec/template/spec/initContainers/env/value
kind: StatefulSet
- path: spec/template/spec/containers/env/value
kind: StatefulSet
- path: spec/template/spec/initContainers/env/value
kind: Deployment
- path: spec/template/spec/containers/env/value
kind: Deployment
- path: spec/template/spec/initContainers/env/value
kind: DaemonSet
- path: spec/template/spec/containers/env/value
kind: DaemonSet
- path: spec/template/spec/containers/env/value
kind: Job
- path: spec/template/spec/initContainers/env/value
kind: Job
- path: spec/jobTemplate/spec/template/spec/containers/env/value - path: spec/jobTemplate/spec/template/spec/containers/env/value
kind: CronJob kind: CronJob
- path: spec/containers/command - path: spec/jobTemplate/spec/template/spec/containers/volumeMounts/mountPath
kind: Pod kind: CronJob
- path: spec/containers/args - path: spec/jobTemplate/spec/template/spec/initContainers/args
kind: Pod kind: CronJob
- path: spec/containers/env/value - path: spec/jobTemplate/spec/template/spec/initContainers/command
kind: Pod kind: CronJob
- path: spec/initContainers/command - path: spec/jobTemplate/spec/template/spec/initContainers/env/value
kind: Pod kind: CronJob
- path: spec/initContainers/args - path: spec/jobTemplate/spec/template/spec/initContainers/volumeMounts/mountPath
kind: Pod kind: CronJob
- path: spec/initContainers/env/value - path: spec/template/spec/containers/args
kind: Pod kind: DaemonSet
- path: spec/template/spec/containers/command
kind: DaemonSet
- path: spec/template/spec/containers/env/value
kind: DaemonSet
- path: spec/template/spec/containers/volumeMounts/mountPath
kind: DaemonSet
- path: spec/template/spec/initContainers/args
kind: DaemonSet
- path: spec/template/spec/initContainers/command
kind: DaemonSet
- path: spec/template/spec/initContainers/env/value
kind: DaemonSet
- path: spec/template/spec/initContainers/volumeMounts/mountPath
kind: DaemonSet
- path: spec/template/spec/containers/args
kind: Deployment
- path: spec/template/spec/containers/command
kind: Deployment
- path: spec/template/spec/containers/env/value
kind: Deployment
- path: spec/template/spec/containers/volumeMounts/mountPath
kind: Deployment
- path: spec/template/spec/initContainers/args
kind: Deployment
- path: spec/template/spec/initContainers/command
kind: Deployment
- path: spec/template/spec/initContainers/env/value
kind: Deployment
- path: spec/template/spec/initContainers/volumeMounts/mountPath
kind: Deployment
- path: spec/rules/host - path: spec/rules/host
kind: Ingress kind: Ingress
@@ -118,47 +97,101 @@ varReference:
- path: spec/tls/hosts - path: spec/tls/hosts
kind: Ingress kind: Ingress
- path: spec/template/spec/containers/args
kind: Job
- path: spec/template/spec/containers/command
kind: Job
- path: spec/template/spec/containers/env/value
kind: Job
- path: spec/template/spec/containers/volumeMounts/mountPath - path: spec/template/spec/containers/volumeMounts/mountPath
kind: StatefulSet kind: Job
- path: spec/template/spec/initContainers/args
kind: Job
- path: spec/template/spec/initContainers/command
kind: Job
- path: spec/template/spec/initContainers/env/value
kind: Job
- path: spec/template/spec/initContainers/volumeMounts/mountPath - path: spec/template/spec/initContainers/volumeMounts/mountPath
kind: StatefulSet kind: Job
- path: spec/containers/args
kind: Pod
- path: spec/containers/command
kind: Pod
- path: spec/containers/env/value
kind: Pod
- path: spec/containers/volumeMounts/mountPath - path: spec/containers/volumeMounts/mountPath
kind: Pod kind: Pod
- path: spec/initContainers/args
kind: Pod
- path: spec/initContainers/command
kind: Pod
- path: spec/initContainers/env/value
kind: Pod
- path: spec/initContainers/volumeMounts/mountPath - path: spec/initContainers/volumeMounts/mountPath
kind: Pod kind: Pod
- path: spec/template/spec/containers/args
kind: ReplicaSet
- path: spec/template/spec/containers/command
kind: ReplicaSet
- path: spec/template/spec/containers/env/value
kind: ReplicaSet
- path: spec/template/spec/containers/volumeMounts/mountPath - path: spec/template/spec/containers/volumeMounts/mountPath
kind: ReplicaSet kind: ReplicaSet
- path: spec/template/spec/initContainers/args
kind: ReplicaSet
- path: spec/template/spec/initContainers/command
kind: ReplicaSet
- path: spec/template/spec/initContainers/env/value
kind: ReplicaSet
- path: spec/template/spec/initContainers/volumeMounts/mountPath - path: spec/template/spec/initContainers/volumeMounts/mountPath
kind: ReplicaSet kind: ReplicaSet
- path: spec/template/spec/containers/volumeMounts/mountPath - path: spec/template/spec/containers/args
kind: Job kind: StatefulSet
- path: spec/template/spec/initContainers/volumeMounts/mountPath - path: spec/template/spec/containers/command
kind: Job kind: StatefulSet
- path: spec/template/spec/containers/env/value
kind: StatefulSet
- path: spec/template/spec/containers/volumeMounts/mountPath - path: spec/template/spec/containers/volumeMounts/mountPath
kind: CronJob kind: StatefulSet
- path: spec/template/spec/initContainers/args
kind: StatefulSet
- path: spec/template/spec/initContainers/command
kind: StatefulSet
- path: spec/template/spec/initContainers/env/value
kind: StatefulSet
- path: spec/template/spec/initContainers/volumeMounts/mountPath - path: spec/template/spec/initContainers/volumeMounts/mountPath
kind: CronJob kind: StatefulSet
- path: spec/template/spec/containers/volumeMounts/mountPath
kind: DaemonSet
- path: spec/template/spec/initContainers/volumeMounts/mountPath
kind: DaemonSet
- path: spec/template/spec/containers/volumeMounts/mountPath
kind: Deployment
- path: spec/template/spec/initContainers/volumeMounts/mountPath
kind: Deployment
- path: metadata/labels - path: metadata/labels
` `

View File

@@ -1,266 +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 transformers
import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/image"
"sigs.k8s.io/kustomize/pkg/resid"
"sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource"
)
func TestImageTransformer(t *testing.T) {
var rf = resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
m := resmap.ResMap{
resid.NewResId(deploy, "deploy1"): rf.FromMap(
map[string]interface{}{
"group": "apps",
"apiVersion": "v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deploy1",
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"initContainers": []interface{}{
map[string]interface{}{
"name": "nginx2",
"image": "my-nginx:1.8.0",
},
map[string]interface{}{
"name": "init-alpine",
"image": "alpine:1.8.0",
},
},
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:1.7.9",
},
map[string]interface{}{
"name": "replaced-with-digest",
"image": "foobar:1",
},
map[string]interface{}{
"name": "postgresdb",
"image": "postgres:1.8.0",
},
},
},
},
},
}),
resid.NewResId(gvk.Gvk{Kind: "randomKind"}, "random"): rf.FromMap(
map[string]interface{}{
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx1",
"image": "nginx",
},
},
},
},
},
"spec2": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx3",
"image": "nginx:v1",
},
map[string]interface{}{
"name": "nginx4",
"image": "my-nginx:latest",
},
},
},
},
},
"spec3": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"initContainers": []interface{}{
map[string]interface{}{
"name": "postgresdb",
"image": "postgres:alpine-9",
},
map[string]interface{}{
"name": "init-docker",
"image": "docker:17-git",
},
map[string]interface{}{
"name": "myimage",
"image": "myprivaterepohostname:1234/my/image:latest",
},
map[string]interface{}{
"name": "myimage2",
"image": "myprivaterepohostname:1234/my/image",
},
map[string]interface{}{
"name": "my-app",
"image": "my-app-image:v1",
},
map[string]interface{}{
"name": "my-cool-app",
"image": "gcr.io:8080/my-project/my-cool-app:latest",
},
},
},
},
},
}),
}
expected := resmap.ResMap{
resid.NewResId(deploy, "deploy1"): rf.FromMap(
map[string]interface{}{
"group": "apps",
"apiVersion": "v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deploy1",
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"initContainers": []interface{}{
map[string]interface{}{
"name": "nginx2",
"image": "my-nginx:previous",
},
map[string]interface{}{
"name": "init-alpine",
"image": "myprivaterepohostname:1234/my/cool-alpine:1.8.0",
},
},
"containers": []interface{}{
map[string]interface{}{
"name": "nginx",
"image": "nginx:v2",
},
map[string]interface{}{
"name": "replaced-with-digest",
"image": "foobar@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3",
},
map[string]interface{}{
"name": "postgresdb",
"image": "my-postgres:v3",
},
},
},
},
},
}),
resid.NewResId(gvk.Gvk{Kind: "randomKind"}, "random"): rf.FromMap(
map[string]interface{}{
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx1",
"image": "nginx:v2",
},
},
},
},
},
"spec2": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "nginx3",
"image": "nginx:v2",
},
map[string]interface{}{
"name": "nginx4",
"image": "my-nginx:previous",
},
},
},
},
},
"spec3": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"initContainers": []interface{}{
map[string]interface{}{
"name": "postgresdb",
"image": "my-postgres:v3",
},
map[string]interface{}{
"name": "init-docker",
"image": "my-docker@sha256:25a0d4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3",
},
map[string]interface{}{
"name": "myimage",
"image": "myprivaterepohostname:1234/my/image:v1.0.1",
},
map[string]interface{}{
"name": "myimage2",
"image": "myprivaterepohostname:1234/my/image:v1.0.1",
},
map[string]interface{}{
"name": "my-app",
"image": "gcr.io/my-project/my-app-image:v1",
},
map[string]interface{}{
"name": "my-cool-app",
"image": "my-cool-app:latest",
},
},
},
},
},
}),
}
it, err := NewImageTransformer([]image.Image{
{Name: "nginx", NewTag: "v2"},
{Name: "my-nginx", NewTag: "previous"},
{Name: "myprivaterepohostname:1234/my/image", NewTag: "v1.0.1"},
{Name: "foobar", Digest: "sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"},
{Name: "alpine", NewName: "myprivaterepohostname:1234/my/cool-alpine"},
{Name: "my-app-image", NewName: "gcr.io/my-project/my-app-image"},
{Name: "gcr.io:8080/my-project/my-cool-app", NewName: "my-cool-app"},
{Name: "postgres", NewName: "my-postgres", NewTag: "v3"},
{Name: "docker", NewName: "my-docker", Digest: "sha256:25a0d4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"},
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
err = it.Transform(m)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !reflect.DeepEqual(m, expected) {
err = expected.ErrorIfNotEqual(m)
t.Fatalf("actual doesn't match expected: %v. Actual %+v", err, m)
}
}

View File

@@ -194,6 +194,25 @@ type GeneratorArgs struct {
KVSources []KVSource `json:",inline,omitempty" yaml:",inline,omitempty"` 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.
type PluginConfig struct {
// DirectoryPath is an absolute path to a
// directory containing kustomize plugins.
// This directory may contain subdirectories
// further categorizing plugins.
DirectoryPath string
// GoEnabled is true if goplugins are enabled.
// See https://golang.org/pkg/plugin
GoEnabled bool
}
// ConfigMapArgs contains the metadata of how to generate a configmap. // ConfigMapArgs contains the metadata of how to generate a configmap.
type ConfigMapArgs struct { type ConfigMapArgs struct {
// GeneratorArgs for the configmap. // GeneratorArgs for the configmap.