diff --git a/k8sdeps/configmapandsecret/configmapfactory.go b/k8sdeps/configmapandsecret/configmapfactory.go index a40792258..27897c705 100644 --- a/k8sdeps/configmapandsecret/configmapfactory.go +++ b/k8sdeps/configmapandsecret/configmapfactory.go @@ -21,8 +21,7 @@ import ( "fmt" "unicode/utf8" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/types" @@ -40,8 +39,8 @@ func NewFactory( } func makeFreshConfigMap( - args *types.ConfigMapArgs) *corev1.ConfigMap { - cm := &corev1.ConfigMap{} + args *types.ConfigMapArgs) *v1.ConfigMap { + cm := &v1.ConfigMap{} cm.APIVersion = "v1" cm.Kind = "ConfigMap" cm.Name = args.Name @@ -52,7 +51,7 @@ func makeFreshConfigMap( // MakeConfigMap returns a new ConfigMap, or nil and an error. func (f *Factory) MakeConfigMap( - args *types.ConfigMapArgs) (*corev1.ConfigMap, error) { + args *types.ConfigMapArgs) (*v1.ConfigMap, error) { all, err := f.loadKvPairs(args.GeneratorArgs) if err != nil { return nil, err diff --git a/k8sdeps/factory.go b/k8sdeps/factory.go deleted file mode 100644 index a422b25a4..000000000 --- a/k8sdeps/factory.go +++ /dev/null @@ -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(), - ) -} diff --git a/k8sdeps/kunstruct/factory.go b/k8sdeps/kunstruct/factory.go index 3c3644c3f..ef40209b9 100644 --- a/k8sdeps/kunstruct/factory.go +++ b/k8sdeps/kunstruct/factory.go @@ -32,13 +32,21 @@ import ( // KunstructuredFactoryImpl hides construction using apimachinery types. type KunstructuredFactoryImpl struct { + generatorMetaArgs *types.GeneratorMetaArgs } var _ ifc.KunstructuredFactory = &KunstructuredFactoryImpl{} // NewKunstructuredFactoryImpl returns a factory. func NewKunstructuredFactoryImpl() ifc.KunstructuredFactory { - return &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. @@ -82,7 +90,10 @@ func (kf *KunstructuredFactoryImpl) MakeConfigMap( ldr ifc.Loader, options *types.GeneratorOptions, 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 { return nil, err } @@ -94,7 +105,10 @@ func (kf *KunstructuredFactoryImpl) MakeSecret( ldr ifc.Loader, options *types.GeneratorOptions, 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 { return nil, err } diff --git a/k8sdeps/kv/plugin/goplugin.go b/k8sdeps/kv/plugin/goplugin.go index 09351fa1a..4b67f9dd2 100644 --- a/k8sdeps/kv/plugin/goplugin.go +++ b/k8sdeps/kv/plugin/goplugin.go @@ -18,40 +18,66 @@ package plugin import ( "fmt" - "os" + "path/filepath" "plugin" + + "sigs.k8s.io/kustomize/pkg/types" ) var _ Factory = &goFactory{} const ( - pluginDir = "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{ + config: c, plugins: make(map[string]KVSource), } } type goFactory struct { + config *types.PluginConfig plugins map[string]KVSource } -func configDir() string { - xdghome := os.Getenv("XDG_CONFIG_HOME") - if len(xdghome) == 0 { - return os.ExpandEnv("$HOME/.config") - } - return xdghome -} - func (p *goFactory) load(name string) (KVSource, error) { if plug, ok := p.plugins[name]; ok { return plug, nil } - goPlugin, err := plugin.Open(fmt.Sprintf("%s/%s/kustomize-%s.so", configDir(), pluginDir, 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 { return nil, err } diff --git a/k8sdeps/kv/plugin/registry.go b/k8sdeps/kv/plugin/registry.go index bf6c8ae0a..9e7447f29 100644 --- a/k8sdeps/kv/plugin/registry.go +++ b/k8sdeps/kv/plugin/registry.go @@ -18,8 +18,10 @@ 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. @@ -28,17 +30,36 @@ type Registry struct { ldr ifc.Loader } -// NewRegistry returns a new Registry loaded with all the factories. -func NewRegistry(ldr ifc.Loader) Registry { +const ( + 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{ ldr: ldr, factories: map[string]Factory{ - "go": newGoFactory(), + "go": newGoFactory(pc), "testonly": newTestonlyFactory(), }, } } +// 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(pluginType, name string) (KVSource, error) { factory, exists := r.factories[pluginType] diff --git a/kustomize.go b/kustomize.go index e17481de9..584b559e8 100644 --- a/kustomize.go +++ b/kustomize.go @@ -19,12 +19,11 @@ package main import ( "os" - "sigs.k8s.io/kustomize/k8sdeps" "sigs.k8s.io/kustomize/pkg/commands" ) func main() { - if err := commands.NewDefaultCommand(k8sdeps.NewFactory()).Execute(); err != nil { + if err := commands.NewDefaultCommand().Execute(); err != nil { os.Exit(1) } os.Exit(0) diff --git a/pkg/commands/build/build.go b/pkg/commands/build/build.go index e62747e32..1176f25b1 100644 --- a/pkg/commands/build/build.go +++ b/pkg/commands/build/build.go @@ -21,10 +21,10 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/ifc/transformer" "sigs.k8s.io/kustomize/pkg/loader" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/target" ) @@ -67,7 +67,7 @@ func NewCmdBuild( cmd := &cobra.Command{ 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, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -88,7 +88,7 @@ func NewCmdBuild( // Validate validates build command. func (o *Options) Validate(args []string) error { 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 { o.kustomizationPath = "./" diff --git a/pkg/commands/build/build_test.go b/pkg/commands/build/build_test.go index b06ccdea2..792d95aac 100644 --- a/pkg/commands/build/build_test.go +++ b/pkg/commands/build/build_test.go @@ -19,7 +19,7 @@ package build import ( "testing" - "sigs.k8s.io/kustomize/pkg/constants" + "sigs.k8s.io/kustomize/pkg/pgmconfig" ) func TestNewOptionsToSilenceCodeInspectionError(t *testing.T) { @@ -39,7 +39,7 @@ func TestBuildValidate(t *testing.T) { {"file", []string{"beans"}, "beans", ""}, {"path", []string{"a/b/c"}, "a/b/c", ""}, {"path", []string{"too", "many"}, - "", "specify one path to " + constants.KustomizationFileNames[0]}, + "", "specify one path to " + pgmconfig.KustomizationFileNames[0]}, } for _, mycase := range cases { opts := Options{} diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 3651ae6cf..5a4ff0d05 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -20,35 +20,57 @@ package commands import ( "flag" "os" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "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/edit" "sigs.k8s.io/kustomize/pkg/commands/misc" - "sigs.k8s.io/kustomize/pkg/factory" "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. -func NewDefaultCommand(f *factory.KustFactory) *cobra.Command { - fsys := fs.MakeRealFS() +func NewDefaultCommand() *cobra.Command { + fSys := fs.MakeRealFS() stdOut := os.Stdout c := &cobra.Command{ - Use: "kustomize", - Short: "kustomize manages declarative configuration of Kubernetes", + Use: pgmconfig.PgmName, + Short: "Manages declarative configuration of Kubernetes", Long: ` -kustomize manages declarative configuration of Kubernetes. - +Manages declarative configuration of Kubernetes. 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( - // TODO: Make consistent API for newCmd* functions. - build.NewCmdBuild(stdOut, fsys, f.ResmapF, f.TransformerF), - edit.NewCmdEdit(fsys, f.ValidatorF, f.UnstructF), - misc.NewCmdConfig(fsys), + build.NewCmdBuild( + stdOut, fSys, + resmap.NewFactory(resource.NewFactory(uf)), + transformer.NewFactoryImpl()), + edit.NewCmdEdit(fSys, validator.NewKustValidator(), uf), + misc.NewCmdConfig(fSys), misc.NewCmdVersion(stdOut), ) c.PersistentFlags().AddGoFlagSet(flag.CommandLine) diff --git a/pkg/commands/edit/add/addmetadata.go b/pkg/commands/edit/add/addmetadata.go index d9104f35d..b4e14f34e 100644 --- a/pkg/commands/edit/add/addmetadata.go +++ b/pkg/commands/edit/add/addmetadata.go @@ -22,8 +22,8 @@ import ( "github.com/spf13/cobra" "sigs.k8s.io/kustomize/pkg/commands/kustfile" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "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 cmd := &cobra.Command{ Use: "annotation", - Short: "Adds one or more commonAnnotations to " + constants.KustomizationFileNames[0], + Short: "Adds one or more commonAnnotations to " + pgmconfig.KustomizationFileNames[0], Example: ` add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}`, 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 cmd := &cobra.Command{ Use: "label", - Short: "Adds one or more commonLabels to " + constants.KustomizationFileNames[0], + Short: "Adds one or more commonLabels to " + pgmconfig.KustomizationFileNames[0], Example: ` add label {labelKey1:labelValue1},{labelKey2:labelValue2}`, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/pkg/commands/kustfile/kustomizationfile.go b/pkg/commands/kustfile/kustomizationfile.go index cf66745ec..42b93d789 100644 --- a/pkg/commands/kustfile/kustomizationfile.go +++ b/pkg/commands/kustfile/kustomizationfile.go @@ -27,8 +27,8 @@ import ( "strings" "github.com/ghodss/yaml" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/types" ) @@ -129,7 +129,7 @@ func NewKustomizationFile(fSys fs.FileSystem) (*kustomizationFile, error) { // n func (mf *kustomizationFile) validate() error { match := 0 var path []string - for _, kfilename := range constants.KustomizationFileNames { + for _, kfilename := range pgmconfig.KustomizationFileNames { if mf.fSys.Exists(kfilename) { match += 1 path = append(path, kfilename) @@ -138,7 +138,7 @@ func (mf *kustomizationFile) validate() error { switch match { 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: mf.path = path[0] default: diff --git a/pkg/commands/kustfile/kustomizationfile_test.go b/pkg/commands/kustfile/kustomizationfile_test.go index 79e3a5da3..0795986c3 100644 --- a/pkg/commands/kustfile/kustomizationfile_test.go +++ b/pkg/commands/kustfile/kustomizationfile_test.go @@ -21,8 +21,8 @@ import ( "strings" "testing" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/types" ) @@ -112,12 +112,12 @@ configMapGenerator: name: my-configmap ` fakeFS := fs.MakeFakeFS() - fakeFS.WriteFile(constants.KustomizationFileNames[1], []byte(kcontent)) + fakeFS.WriteFile(pgmconfig.KustomizationFileNames[1], []byte(kcontent)) k, err := NewKustomizationFile(fakeFS) if err != nil { 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) } } diff --git a/pkg/factory/factory.go b/pkg/factory/factory.go deleted file mode 100644 index e71669a87..000000000 --- a/pkg/factory/factory.go +++ /dev/null @@ -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, - } -} diff --git a/pkg/fs/fakefs.go b/pkg/fs/fakefs.go index 59c0966b2..0f2a4eedf 100644 --- a/pkg/fs/fakefs.go +++ b/pkg/fs/fakefs.go @@ -22,7 +22,7 @@ import ( "sort" "strings" - "sigs.k8s.io/kustomize/pkg/constants" + "sigs.k8s.io/kustomize/pkg/pgmconfig" ) var _ FileSystem = &fakeFs{} @@ -158,7 +158,7 @@ func (fs *fakeFs) ReadFile(name string) ([]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. @@ -176,7 +176,7 @@ func (fs *fakeFs) WriteTestKustomization() { // WriteTestKustomizationWith writes a standard test file. 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 { diff --git a/pkg/loader/fileloader_test.go b/pkg/loader/fileloader_test.go index b8affe10e..68114f368 100644 --- a/pkg/loader/fileloader_test.go +++ b/pkg/loader/fileloader_test.go @@ -25,8 +25,8 @@ import ( "strings" "testing" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/git" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/ifc" @@ -341,7 +341,7 @@ func TestNewLoaderAtGitClone(t *testing.T) { fSys.MkdirAll(coRoot) fSys.MkdirAll(coRoot + "/" + pathInRepo) fSys.WriteFile( - coRoot+"/"+pathInRepo+"/"+constants.KustomizationFileNames[0], + coRoot+"/"+pathInRepo+"/"+pgmconfig.KustomizationFileNames[0], []byte(` whatever `)) diff --git a/pkg/pgmconfig/config.go b/pkg/pgmconfig/config.go new file mode 100644 index 000000000..d7a27422a --- /dev/null +++ b/pkg/pgmconfig/config.go @@ -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" +} diff --git a/pkg/pgmconfig/config_test.go b/pkg/pgmconfig/config_test.go new file mode 100644 index 000000000..2833afea7 --- /dev/null +++ b/pkg/pgmconfig/config_test.go @@ -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) + } +} diff --git a/pkg/constants/constants.go b/pkg/pgmconfig/constants.go similarity index 76% rename from pkg/constants/constants.go rename to pkg/pgmconfig/constants.go index dd50230fb..008b69da9 100644 --- a/pkg/constants/constants.go +++ b/pkg/pgmconfig/constants.go @@ -15,14 +15,18 @@ limitations under the License. */ // 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 -// by Kustomize. -// In each directory, Kustomize searches for file with the name in this list. -// Only one match is allowed. +// KustomizationFileNames is a list of filenames +// that kustomize recognizes. +// To avoid ambiguity, a directory cannot contain +// more than one match to this list. var KustomizationFileNames = []string{ "kustomization.yaml", "kustomization.yml", "Kustomization", } + +const ( + PgmName = "kustomize" +) diff --git a/pkg/target/generatoroptions_test.go b/pkg/target/generatoroptions_test.go index 4dbdbb588..fc1bd792e 100644 --- a/pkg/target/generatoroptions_test.go +++ b/pkg/target/generatoroptions_test.go @@ -14,6 +14,9 @@ limitations under the License. package target_test import ( + "path/filepath" + "sigs.k8s.io/kustomize/pkg/types" + "strings" "testing" ) @@ -69,3 +72,47 @@ metadata: 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) + } +} diff --git a/pkg/target/kusttarget.go b/pkg/target/kusttarget.go index 5bbd2198c..6a6eb952b 100644 --- a/pkg/target/kusttarget.go +++ b/pkg/target/kusttarget.go @@ -25,11 +25,11 @@ import ( "github.com/ghodss/yaml" "github.com/pkg/errors" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc/transformer" interror "sigs.k8s.io/kustomize/pkg/internal/error" 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/resource" "sigs.k8s.io/kustomize/pkg/transformers" @@ -89,7 +89,7 @@ func commaOr(q []string) string { func loadKustFile(ldr ifc.Loader) ([]byte, error) { var content []byte match := 0 - for _, kf := range constants.KustomizationFileNames { + for _, kf := range pgmconfig.KustomizationFileNames { c, err := ldr.Load(kf) if err == nil { match += 1 @@ -100,7 +100,7 @@ func loadKustFile(ldr ifc.Loader) ([]byte, error) { case 0: return nil, fmt.Errorf( "unable to find one of %v in directory '%s'", - commaOr(quoted(constants.KustomizationFileNames)), ldr.Root()) + commaOr(quoted(pgmconfig.KustomizationFileNames)), ldr.Root()) case 1: return content, nil default: diff --git a/pkg/target/kusttestharness_test.go b/pkg/target/kusttestharness_test.go index 74cbab348..ea3b712bd 100644 --- a/pkg/target/kusttestharness_test.go +++ b/pkg/target/kusttestharness_test.go @@ -21,13 +21,14 @@ package target_test import ( "fmt" "path/filepath" + "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "strings" "testing" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/transformer" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/internal/loadertest" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" . "sigs.k8s.io/kustomize/pkg/target" @@ -42,10 +43,18 @@ type KustTestHarness struct { } 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{ t: t, rf: resmap.NewFactory(resource.NewFactory( - kunstruct.NewKunstructuredFactoryImpl())), + kunstruct.NewKunstructuredFactoryWithGeneratorArgs( + &types.GeneratorMetaArgs{PluginConfig: config}))), ldr: loadertest.NewFakeLoader(path)} } @@ -66,7 +75,7 @@ func (th *KustTestHarness) writeF(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 kind: Kustomization `+content) diff --git a/pkg/types/kustomization.go b/pkg/types/kustomization.go index c92867422..39a08700d 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -194,6 +194,25 @@ type GeneratorArgs struct { 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. type ConfigMapArgs struct { // GeneratorArgs for the configmap.