From b553997447e88241dc84a5ab8daddf8c63629e3f Mon Sep 17 00:00:00 2001 From: monopole Date: Fri, 12 Feb 2021 10:53:22 -0800 Subject: [PATCH] Make more high level build methods public. --- api/krusty/kustomizer.go | 31 ++-- api/krusty/kustomizer_test.go | 5 +- api/krusty/remoteload_test.go | 3 +- api/testutils/kusttest/harness.go | 4 +- kustomize/commands/build/build.go | 140 +++++------------- kustomize/commands/build/flagaddmanagedby.go | 2 +- .../build/flagallowresourceidchanges.go | 2 +- kustomize/commands/build/flagenableplugins.go | 2 +- .../commands/build/flagloadrestrictor.go | 2 +- kustomize/commands/build/flagsforfunctions.go | 30 ++++ kustomize/commands/build/reorderoutput.go | 2 +- kustomize/commands/build/writer.go | 59 ++++++++ 12 files changed, 152 insertions(+), 130 deletions(-) create mode 100644 kustomize/commands/build/flagsforfunctions.go create mode 100644 kustomize/commands/build/writer.go diff --git a/api/krusty/kustomizer.go b/api/krusty/kustomizer.go index 3c52661cf..eec8e6bac 100644 --- a/api/krusty/kustomizer.go +++ b/api/krusty/kustomizer.go @@ -19,22 +19,21 @@ import ( "sigs.k8s.io/kustomize/kyaml/openapi" ) -// Kustomizer performs kustomizations. It's meant to behave -// similarly to the kustomize CLI, and can be used instead of -// performing an exec to a kustomize CLI subprocess. +// Kustomizer performs kustomizations. +// +// It's meant to behave similarly to the kustomize CLI, and can be +// used instead of performing an exec to a kustomize CLI subprocess. // To use, load a filesystem with kustomization files (any // number of overlays and bases), then make a Kustomizer // injected with the given fileystem, then call Run. type Kustomizer struct { - fSys filesys.FileSystem options *Options depProvider *provider.DepProvider } // MakeKustomizer returns an instance of Kustomizer. -func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer { +func MakeKustomizer(o *Options) *Kustomizer { return &Kustomizer{ - fSys: fSys, options: o, depProvider: provider.NewDepProvider(o.UseKyaml), } @@ -42,16 +41,16 @@ func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer { // Run performs a kustomization. // -// It uses its internal filesystem reference to read the file at -// the given path argument, interpret it as a kustomization.yaml -// file, perform the kustomization it represents, and return the -// resulting resources. +// It reads given path from the given file system, interprets it as +// a kustomization.yaml file, perform the kustomization it represents, +// and return the resulting resources. // -// Any files referenced by the kustomization must be present in the -// internal filesystem. One may call Run any number of times, -// on any number of internal paths (e.g. the filesystem may contain -// multiple overlays, and Run can be called on each of them). -func (b *Kustomizer) Run(path string) (resmap.ResMap, error) { +// Any files referenced by the kustomization must be present on the +// filesystem. One may call Run any number of times, on any number +// of internal paths (e.g. the filesystem may contain multiple overlays, +// and Run can be called on each of them). +func (b *Kustomizer) Run( + fSys filesys.FileSystem, path string) (resmap.ResMap, error) { resmapFactory := resmap.NewFactory( b.depProvider.GetResourceFactory(), b.depProvider.GetConflictDetectorFactory()) @@ -59,7 +58,7 @@ func (b *Kustomizer) Run(path string) (resmap.ResMap, error) { if b.options.LoadRestrictions == types.LoadRestrictionsRootOnly { lr = fLdr.RestrictionRootOnly } - ldr, err := fLdr.NewLoader(lr, path, b.fSys) + ldr, err := fLdr.NewLoader(lr, path, fSys) if err != nil { return nil, err } diff --git a/api/krusty/kustomizer_test.go b/api/krusty/kustomizer_test.go index 6742fff84..997ce24da 100644 --- a/api/krusty/kustomizer_test.go +++ b/api/krusty/kustomizer_test.go @@ -16,9 +16,8 @@ import ( // For more substantial tests and examples, // see other tests in this package. func TestEmptyFileSystem(t *testing.T) { - fSys := filesys.MakeFsInMemory() - b := krusty.MakeKustomizer(fSys, krusty.MakeDefaultOptions()) - _, err := b.Run("noSuchThing") + b := krusty.MakeKustomizer(krusty.MakeDefaultOptions()) + _, err := b.Run(filesys.MakeFsInMemory(), "noSuchThing") if err == nil { t.Fatalf("expected error") } diff --git a/api/krusty/remoteload_test.go b/api/krusty/remoteload_test.go index 0c33fec10..73dae9109 100644 --- a/api/krusty/remoteload_test.go +++ b/api/krusty/remoteload_test.go @@ -14,8 +14,9 @@ import ( func TestRemoteLoad(t *testing.T) { fSys := filesys.MakeFsOnDisk() - b := krusty.MakeKustomizer(fSys, krusty.MakeDefaultOptions()) + b := krusty.MakeKustomizer(krusty.MakeDefaultOptions()) m, err := b.Run( + fSys, "github.com/kubernetes-sigs/kustomize/examples/multibases/dev/?ref=v1.0.6") if utils.IsErrTimeout(err) { // Don't fail on timeouts. diff --git a/api/testutils/kusttest/harness.go b/api/testutils/kusttest/harness.go index 8ff164e0b..a3adbe6dd 100644 --- a/api/testutils/kusttest/harness.go +++ b/api/testutils/kusttest/harness.go @@ -93,7 +93,7 @@ func (th Harness) MakeOptionsPluginsEnabled() krusty.Options { // Run, failing on error. func (th Harness) Run(path string, o krusty.Options) resmap.ResMap { - m, err := krusty.MakeKustomizer(th.fSys, &o).Run(path) + m, err := krusty.MakeKustomizer(&o).Run(th.fSys, path) if err != nil { th.t.Fatal(err) } @@ -102,7 +102,7 @@ func (th Harness) Run(path string, o krusty.Options) resmap.ResMap { // Run, failing if there is no error. func (th Harness) RunWithErr(path string, o krusty.Options) error { - _, err := krusty.MakeKustomizer(th.fSys, &o).Run(path) + _, err := krusty.MakeKustomizer(&o).Run(th.fSys, path) if err == nil { th.t.Fatalf("expected error") } diff --git a/kustomize/commands/build/build.go b/kustomize/commands/build/build.go index 82ee10dce..242cd3bc8 100644 --- a/kustomize/commands/build/build.go +++ b/kustomize/commands/build/build.go @@ -7,18 +7,13 @@ import ( "fmt" "io" "log" - "path/filepath" - "strings" "github.com/pkg/errors" "github.com/spf13/cobra" "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/krusty" - "sigs.k8s.io/kustomize/api/resmap" - "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" - "sigs.k8s.io/yaml" ) // Options contain the options for running a build @@ -78,11 +73,31 @@ func NewCmdBuild(help Help, out io.Writer) *cobra.Command { Example: help.Example, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { - err := o.Validate(args) + if err := o.Validate(args); err != nil { + return err + } + k := krusty.MakeKustomizer( + o.ModifyKrustyOptions(krusty.MakeDefaultOptions()), + ) + fSys := filesys.MakeFsOnDisk() + m, err := k.Run(fSys, o.kustomizationPath) if err != nil { return err } - return o.RunBuild(out) + if o.outputPath != "" && fSys.IsDir(o.outputPath) { + // Ignore io.Writer; write to o.outputPath directly. + return MakeWriter(fSys).WriteIndividualFiles(o.outputPath, m) + } + yml, err := m.AsYaml() + if err != nil { + return err + } + if o.outputPath != "" { + // Ignore io.Writer; write to o.outputPath directly. + return fSys.WriteFile(o.outputPath, yml) + } + _, err = out.Write(yml) + return err }, } @@ -90,30 +105,13 @@ func NewCmdBuild(help Help, out io.Writer) *cobra.Command { &o.outputPath, "output", "o", "", "If specified, write output to this path.") - cmd.Flags().BoolVar( - &o.fnOptions.EnableExec, "enable-exec", false, /*do not change!*/ - "enable support for exec functions -- note: exec functions run arbitrary code -- do not use for untrusted configs!!! (Alpha)") - cmd.Flags().BoolVar( - &o.fnOptions.EnableStar, "enable-star", false, - "enable support for starlark functions. (Alpha)") - cmd.Flags().BoolVar( - &o.fnOptions.Network, "network", false, - "enable network access for functions that declare it") - cmd.Flags().StringVar( - &o.fnOptions.NetworkName, "network-name", "bridge", - "the docker network to run the container in") - cmd.Flags().StringArrayVar( - &o.fnOptions.Mounts, "mount", []string{}, - "a list of storage options read from the filesystem") - cmd.Flags().StringArrayVarP( - &o.fnOptions.Env, "env", "e", []string{}, - "a list of environment variables to be used by functions") - addFlagLoadRestrictor(cmd.Flags()) - addFlagEnablePlugins(cmd.Flags()) - addFlagReorderOutput(cmd.Flags()) - addFlagEnableManagedbyLabel(cmd.Flags()) - addFlagAllowResourceIdChanges(cmd.Flags()) + AddFunctionFlags(cmd.Flags(), &o.fnOptions) + AddFlagLoadRestrictor(cmd.Flags()) + AddFlagEnablePlugins(cmd.Flags()) + AddFlagReorderOutput(cmd.Flags()) + AddFlagEnableManagedbyLabel(cmd.Flags()) + AddFlagAllowResourceIdChanges(cmd.Flags()) return cmd } @@ -138,84 +136,20 @@ func (o *Options) Validate(args []string) (err error) { return } -func (o *Options) makeOptions() *krusty.Options { - opts := krusty.MakeDefaultOptions() - opts.DoLegacyResourceSort = o.outOrder == legacy - opts.LoadRestrictions = getFlagLoadRestrictorValue() +// ModifyKrustyOptions feeds command line data into the krusty options. +func (o *Options) ModifyKrustyOptions(kOpts *krusty.Options) *krusty.Options { + kOpts.DoLegacyResourceSort = o.outOrder == legacy + kOpts.LoadRestrictions = getFlagLoadRestrictorValue() if isFlagEnablePluginsSet() { c, err := konfig.EnabledPluginConfig(types.BploUseStaticallyLinked) if err != nil { log.Fatal(err) } c.FnpLoadingOptions = o.fnOptions - opts.PluginConfig = c + kOpts.PluginConfig = c } - opts.AddManagedbyLabel = isManagedbyLabelEnabled() - opts.UseKyaml = konfig.FlagEnableKyamlDefaultValue - opts.AllowResourceIdChanges = flagAllowResourceIdChangesValue - return opts -} - -func (o *Options) RunBuild(out io.Writer) error { - fSys := filesys.MakeFsOnDisk() - k := krusty.MakeKustomizer(fSys, o.makeOptions()) - m, err := k.Run(o.kustomizationPath) - if err != nil { - return err - } - return o.emitResources(out, fSys, m) -} - -func (o *Options) emitResources( - out io.Writer, fSys filesys.FileSystem, m resmap.ResMap) error { - if o.outputPath != "" && fSys.IsDir(o.outputPath) { - return writeIndividualFiles(fSys, o.outputPath, m) - } - res, err := m.AsYaml() - if err != nil { - return err - } - if o.outputPath != "" { - return fSys.WriteFile(o.outputPath, res) - } - _, err = out.Write(res) - return err -} - -func writeIndividualFiles( - fSys filesys.FileSystem, folderPath string, m resmap.ResMap) error { - byNamespace := m.GroupedByCurrentNamespace() - for namespace, resList := range byNamespace { - for _, res := range resList { - fName := fileName(res) - if len(byNamespace) > 1 { - fName = strings.ToLower(namespace) + "_" + fName - } - err := writeFile(fSys, folderPath, fName, res) - if err != nil { - return err - } - } - } - for _, res := range m.NonNamespaceable() { - err := writeFile(fSys, folderPath, fileName(res), res) - if err != nil { - return err - } - } - return nil -} - -func fileName(res *resource.Resource) string { - return strings.ToLower(res.GetGvk().StringWoEmptyField()) + - "_" + strings.ToLower(res.GetName()) + ".yaml" -} - -func writeFile( - fSys filesys.FileSystem, path, fName string, res *resource.Resource) error { - out, err := yaml.Marshal(res.Map()) - if err != nil { - return err - } - return fSys.WriteFile(filepath.Join(path, fName), out) + kOpts.AddManagedbyLabel = isManagedbyLabelEnabled() + kOpts.UseKyaml = konfig.FlagEnableKyamlDefaultValue + kOpts.AllowResourceIdChanges = flagAllowResourceIdChangesValue + return kOpts } diff --git a/kustomize/commands/build/flagaddmanagedby.go b/kustomize/commands/build/flagaddmanagedby.go index 807d7ee64..f8622e0aa 100644 --- a/kustomize/commands/build/flagaddmanagedby.go +++ b/kustomize/commands/build/flagaddmanagedby.go @@ -19,7 +19,7 @@ var ( flagEnableManagedbyLabelValue = false ) -func addFlagEnableManagedbyLabel(set *pflag.FlagSet) { +func AddFlagEnableManagedbyLabel(set *pflag.FlagSet) { set.BoolVar( &flagEnableManagedbyLabelValue, flagEnableManagedbyLabelName, false, flagEnableManagedbyLabelHelp) diff --git a/kustomize/commands/build/flagallowresourceidchanges.go b/kustomize/commands/build/flagallowresourceidchanges.go index 5a9240e90..69b270d4c 100644 --- a/kustomize/commands/build/flagallowresourceidchanges.go +++ b/kustomize/commands/build/flagallowresourceidchanges.go @@ -16,7 +16,7 @@ var ( flagAllowResourceIdChangesValue = false ) -func addFlagAllowResourceIdChanges(set *pflag.FlagSet) { +func AddFlagAllowResourceIdChanges(set *pflag.FlagSet) { set.BoolVar( &flagAllowResourceIdChangesValue, flagAllowResourceIdChangesName, false, flagAllowResourceIdChangesHelp) diff --git a/kustomize/commands/build/flagenableplugins.go b/kustomize/commands/build/flagenableplugins.go index a9c0eed05..2ee067599 100644 --- a/kustomize/commands/build/flagenableplugins.go +++ b/kustomize/commands/build/flagenableplugins.go @@ -18,7 +18,7 @@ var ( flagPluginsEnabledValue = false ) -func addFlagEnablePlugins(set *pflag.FlagSet) { +func AddFlagEnablePlugins(set *pflag.FlagSet) { set.BoolVar( &flagPluginsEnabledValue, flagEnablePluginsName, false, flagEnablePluginsHelp) diff --git a/kustomize/commands/build/flagloadrestrictor.go b/kustomize/commands/build/flagloadrestrictor.go index 059d5118e..14d11a6a0 100644 --- a/kustomize/commands/build/flagloadrestrictor.go +++ b/kustomize/commands/build/flagloadrestrictor.go @@ -21,7 +21,7 @@ var ( "This does, however, break the relocatability of the kustomization." ) -func addFlagLoadRestrictor(set *pflag.FlagSet) { +func AddFlagLoadRestrictor(set *pflag.FlagSet) { set.StringVar( &flagLrValue, flagName, types.LoadRestrictionsRootOnly.String(), flagLrHelp) diff --git a/kustomize/commands/build/flagsforfunctions.go b/kustomize/commands/build/flagsforfunctions.go new file mode 100644 index 000000000..2fccffa15 --- /dev/null +++ b/kustomize/commands/build/flagsforfunctions.go @@ -0,0 +1,30 @@ +// Copyright 2021 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "github.com/spf13/pflag" + "sigs.k8s.io/kustomize/api/types" +) + +func AddFunctionFlags(set *pflag.FlagSet, o *types.FnPluginLoadingOptions) { + set.BoolVar( + &o.EnableExec, "enable-exec", false, /*do not change!*/ + "enable support for exec functions -- note: exec functions run arbitrary code -- do not use for untrusted configs!!! (Alpha)") + set.BoolVar( + &o.EnableStar, "enable-star", false, + "enable support for starlark functions. (Alpha)") + set.BoolVar( + &o.Network, "network", false, + "enable network access for functions that declare it") + set.StringVar( + &o.NetworkName, "network-name", "bridge", + "the docker network to run the container in") + set.StringArrayVar( + &o.Mounts, "mount", []string{}, + "a list of storage options read from the filesystem") + set.StringArrayVarP( + &o.Env, "env", "e", []string{}, + "a list of environment variables to be used by functions") +} diff --git a/kustomize/commands/build/reorderoutput.go b/kustomize/commands/build/reorderoutput.go index 63ed2ec30..abd061603 100644 --- a/kustomize/commands/build/reorderoutput.go +++ b/kustomize/commands/build/reorderoutput.go @@ -29,7 +29,7 @@ var ( "Use '" + none.String() + "' to suppress a final reordering." ) -func addFlagReorderOutput(set *pflag.FlagSet) { +func AddFlagReorderOutput(set *pflag.FlagSet) { set.StringVar( &flagReorderOutputValue, flagReorderOutputName, legacy.String(), flagReorderOutputHelp) diff --git a/kustomize/commands/build/writer.go b/kustomize/commands/build/writer.go new file mode 100644 index 000000000..0ead0ddac --- /dev/null +++ b/kustomize/commands/build/writer.go @@ -0,0 +1,59 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "path/filepath" + "strings" + + "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/api/resource" + "sigs.k8s.io/yaml" +) + +type Writer struct { + fSys filesys.FileSystem +} + +func MakeWriter(fSys filesys.FileSystem) *Writer { + return &Writer{ + fSys: fSys, + } +} + +func (w Writer) WriteIndividualFiles(dirPath string, m resmap.ResMap) error { + byNamespace := m.GroupedByCurrentNamespace() + for namespace, resList := range byNamespace { + for _, res := range resList { + fName := fileName(res) + if len(byNamespace) > 1 { + fName = strings.ToLower(namespace) + "_" + fName + } + if err := w.write(dirPath, fName, res); err != nil { + return err + } + } + } + for _, res := range m.NonNamespaceable() { + err := w.write(dirPath, fileName(res), res) + if err != nil { + return err + } + } + return nil +} + +func (w Writer) write(path, fName string, res *resource.Resource) error { + yml, err := yaml.Marshal(res.Map()) + if err != nil { + return err + } + return w.fSys.WriteFile(filepath.Join(path, fName), yml) +} + +func fileName(res *resource.Resource) string { + return strings.ToLower(res.GetGvk().StringWoEmptyField()) + + "_" + strings.ToLower(res.GetName()) + ".yaml" +}