From 580de7ee2da1d947abebff8a1e2f183a8eafcbf9 Mon Sep 17 00:00:00 2001 From: Richard Marshall Date: Thu, 26 Apr 2018 07:38:07 -0700 Subject: [PATCH] Add subcommand for adding patches to the kustomization file. --- commands/addpatch.go | 96 ++++++++++++++++++++++++++++++++++++ commands/addpatch_test.go | 94 +++++++++++++++++++++++++++++++++++ commands/addresource.go | 9 ---- commands/addresource_test.go | 7 ++- commands/commands.go | 4 ++ commands/util.go | 9 ++++ 6 files changed, 206 insertions(+), 13 deletions(-) create mode 100644 commands/addpatch.go create mode 100644 commands/addpatch_test.go diff --git a/commands/addpatch.go b/commands/addpatch.go new file mode 100644 index 000000000..b1f03c138 --- /dev/null +++ b/commands/addpatch.go @@ -0,0 +1,96 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package commands + +import ( + "errors" + "fmt" + "io" + + "github.com/spf13/cobra" + + "k8s.io/kubectl/pkg/kustomize/constants" + "k8s.io/kubectl/pkg/kustomize/util/fs" +) + +type addPatchOptions struct { + patchFilePath string +} + +// newCmdAddPatch adds the name of a file containing a patch to the kustomization file. +func newCmdAddPatch(out, errOut io.Writer, fsys fs.FileSystem) *cobra.Command { + var o addPatchOptions + + cmd := &cobra.Command{ + Use: "patch", + Short: "Add the name of a file containing a patch to the kustomization file.", + Example: ` + add patch {filepath}`, + RunE: func(cmd *cobra.Command, args []string) error { + err := o.Validate(args) + if err != nil { + return err + } + err = o.Complete(cmd, args) + if err != nil { + return err + } + return o.RunAddPatch(out, errOut, fsys) + }, + } + return cmd +} + +// Validate validates addPatch command. +func (o *addPatchOptions) Validate(args []string) error { + if len(args) != 1 { + return errors.New("must specify a patch file") + } + o.patchFilePath = args[0] + return nil +} + +// Complete completes addPatch command. +func (o *addPatchOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +// RunAddPatch runs addPatch command (do real work). +func (o *addPatchOptions) RunAddPatch(out, errOut io.Writer, fsys fs.FileSystem) error { + _, err := fsys.Stat(o.patchFilePath) + if err != nil { + return err + } + + mf, err := newKustomizationFile(constants.KustomizationFileName, fsys) + if err != nil { + return err + } + + m, err := mf.read() + if err != nil { + return err + } + + if stringInSlice(o.patchFilePath, m.Patches) { + return fmt.Errorf("patch %s already in kustomization file", o.patchFilePath) + } + + m.Patches = append(m.Patches, o.patchFilePath) + + return mf.write(m) +} diff --git a/commands/addpatch_test.go b/commands/addpatch_test.go new file mode 100644 index 000000000..b35b17fbf --- /dev/null +++ b/commands/addpatch_test.go @@ -0,0 +1,94 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package commands + +import ( + "bytes" + "os" + "testing" + + "strings" + + "k8s.io/kubectl/pkg/kustomize/constants" + "k8s.io/kubectl/pkg/kustomize/util/fs" +) + +const ( + patchFileName = "myWonderfulPatch.yaml" + patchFileContent = ` +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +` +) + +func TestAddPatchHappyPath(t *testing.T) { + buf := bytes.NewBuffer([]byte{}) + fakeFS := fs.MakeFakeFS() + fakeFS.WriteFile(patchFileName, []byte(patchFileContent)) + fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent)) + + cmd := newCmdAddPatch(buf, os.Stderr, fakeFS) + args := []string{patchFileName} + err := cmd.RunE(cmd, args) + if err != nil { + t.Errorf("unexpected cmd error: %v", err) + } + content, err := fakeFS.ReadFile(constants.KustomizationFileName) + if err != nil { + t.Errorf("unexpected read error: %v", err) + } + if !strings.Contains(string(content), patchFileName) { + t.Errorf("expected patch name in kustomization") + } +} + +func TestAddPatchAlreadyThere(t *testing.T) { + buf := bytes.NewBuffer([]byte{}) + fakeFS := fs.MakeFakeFS() + fakeFS.WriteFile(patchFileName, []byte(patchFileContent)) + fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent)) + + cmd := newCmdAddPatch(buf, os.Stderr, fakeFS) + args := []string{patchFileName} + err := cmd.RunE(cmd, args) + if err != nil { + t.Fatalf("unexpected cmd error: %v", err) + } + + // adding an existing patch should return an error + err = cmd.RunE(cmd, args) + if err == nil { + t.Errorf("expected already there problem") + } + if err.Error() != "patch "+patchFileName+" already in kustomization file" { + t.Errorf("unexpected error %v", err) + } +} + +func TestAddPatchNoArgs(t *testing.T) { + buf := bytes.NewBuffer([]byte{}) + fakeFS := fs.MakeFakeFS() + + cmd := newCmdAddPatch(buf, os.Stderr, fakeFS) + err := cmd.Execute() + if err == nil { + t.Errorf("expected error: %v", err) + } + if err.Error() != "must specify a patch file" { + t.Errorf("incorrect error: %v", err.Error()) + } +} diff --git a/commands/addresource.go b/commands/addresource.go index 44e22a3bf..41bfcb933 100644 --- a/commands/addresource.go +++ b/commands/addresource.go @@ -69,15 +69,6 @@ func (o *addResourceOptions) Complete(cmd *cobra.Command, args []string) error { return nil } -func stringInSlice(str string, list []string) bool { - for _, v := range list { - if v == str { - return true - } - } - return false -} - // RunAddResource runs addResource command (do real work). func (o *addResourceOptions) RunAddResource(out, errOut io.Writer, fsys fs.FileSystem) error { _, err := fsys.Stat(o.resourceFilePath) diff --git a/commands/addresource_test.go b/commands/addresource_test.go index 1c3dd5b04..81d512540 100644 --- a/commands/addresource_test.go +++ b/commands/addresource_test.go @@ -33,14 +33,13 @@ const ( Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ` - kustomizationContent = `kustomizationName: helloworld -namePrefix: some-prefix + kustomizationContent = `namePrefix: some-prefix # Labels to add to all objects and selectors. # These labels would also be used to form the selector for apply --prune # Named differently than “labels” to avoid confusion with metadata for this object -objectLabels: +commonLabels: app: helloworld -objectAnnotations: +commonAnnotations: note: This is an example annotation resources: [] #- service.yaml diff --git a/commands/commands.go b/commands/commands.go index 40f8a87d2..049b97b5a 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -92,11 +92,15 @@ func newCmdAdd(stdOut, stdErr io.Writer, fsys fs.FileSystem) *cobra.Command { # Adds a resource to the kustomization kustomize edit add resource + + # Adds a patch to the kustomization + kustomize edit add patch `, Args: cobra.MinimumNArgs(1), } c.AddCommand( newCmdAddResource(stdOut, stdErr, fsys), + newCmdAddPatch(stdOut, stdErr, fsys), newCmdAddConfigMap(stdErr, fsys), ) return c diff --git a/commands/util.go b/commands/util.go index 160848341..3df01fa68 100644 --- a/commands/util.go +++ b/commands/util.go @@ -93,3 +93,12 @@ func (mf *kustomizationFile) write(kustomization *types.Kustomization) error { return mf.fsys.WriteFile(mf.path, bytes) } + +func stringInSlice(str string, list []string) bool { + for _, v := range list { + if v == str { + return true + } + } + return false +}