From 158f754f18ef983faa7e9589ebd0f7c6597bbce3 Mon Sep 17 00:00:00 2001 From: Takuro Wada Date: Sun, 23 Jun 2019 18:41:24 +0900 Subject: [PATCH] Add remove annotation command --- k8sdeps/validator/validators.go | 17 ++ pkg/commands/edit/remove/all.go | 4 + pkg/commands/edit/remove/removemetadata.go | 20 +++ .../edit/remove/removemetadata_test.go | 148 ++++++++++++++++++ pkg/ifc/ifc.go | 1 + 5 files changed, 190 insertions(+) diff --git a/k8sdeps/validator/validators.go b/k8sdeps/validator/validators.go index 6c4645202..7ac71ecea 100644 --- a/k8sdeps/validator/validators.go +++ b/k8sdeps/validator/validators.go @@ -53,6 +53,23 @@ func (v *KustValidator) MakeAnnotationValidator() func(map[string]string) error } } +// MakeAnnotationNameValidator returns a MapValidatorFunc using apimachinery. +func (v *KustValidator) MakeAnnotationNameValidator() func([]string) error { + return func(x []string) error { + errs := field.ErrorList{} + fldPath := field.NewPath("field") + for _, k := range x { + for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) { + errs = append(errs, field.Invalid(fldPath, k, msg)) + } + } + if len(errs) > 0 { + return errors.New(errs.ToAggregate().Error()) + } + return nil + } +} + // MakeLabelValidator returns a MapValidatorFunc using apimachinery. func (v *KustValidator) MakeLabelValidator() func(map[string]string) error { return func(x map[string]string) error { diff --git a/pkg/commands/edit/remove/all.go b/pkg/commands/edit/remove/all.go index efa27307f..7a425d081 100644 --- a/pkg/commands/edit/remove/all.go +++ b/pkg/commands/edit/remove/all.go @@ -37,12 +37,16 @@ func NewCmdRemove( # Removes one or more commonLabels from the kustomization file kustomize edit remove label {labelKey1},{labelKey2} + + # Removes one or more commonAnnotations from the kustomization file + kustomize edit remove annotation {annotationKey1},{annotationKey2} `, Args: cobra.MinimumNArgs(1), } c.AddCommand( newCmdRemoveResource(fsys), newCmdRemoveLabel(fsys, ldr.Validator().MakeLabelNameValidator()), + newCmdRemoveAnnotation(fsys, ldr.Validator().MakeAnnotationNameValidator()), ) return c } diff --git a/pkg/commands/edit/remove/removemetadata.go b/pkg/commands/edit/remove/removemetadata.go index dbf71b5b5..df2c73dca 100644 --- a/pkg/commands/edit/remove/removemetadata.go +++ b/pkg/commands/edit/remove/removemetadata.go @@ -52,6 +52,26 @@ type removeMetadataOptions struct { kind kindOfAdd } +// newCmdRemoveLabel removes one or more commonAnnotations from the kustomization file. +func newCmdRemoveAnnotation(fSys fs.FileSystem, v func([]string) error) *cobra.Command { + var o removeMetadataOptions + o.kind = label + o.arrayValidator = v + cmd := &cobra.Command{ + Use: "annotation", + Short: "Removes one or more commonAnnotations from " + pgmconfig.KustomizationFileNames[0], + Example: ` + remove annotation {annotationKey1},{annotationKey2}`, + RunE: func(cmd *cobra.Command, args []string) error { + return o.runE(args, fSys, o.removeAnnotations) + }, + } + cmd.Flags().BoolVarP(&o.ignore, "ignore-non-existence", "i", false, + "ignore error if the given label doesn't exist", + ) + return cmd +} + // newCmdRemoveLabel removes one or more commonLabels from the kustomization file. func newCmdRemoveLabel(fSys fs.FileSystem, v func([]string) error) *cobra.Command { var o removeMetadataOptions diff --git a/pkg/commands/edit/remove/removemetadata_test.go b/pkg/commands/edit/remove/removemetadata_test.go index bffd01506..f431ae49b 100644 --- a/pkg/commands/edit/remove/removemetadata_test.go +++ b/pkg/commands/edit/remove/removemetadata_test.go @@ -54,6 +54,154 @@ func makeKustomization(t *testing.T) *types.Kustomization { return readKustomizationFS(t, fakeFS) } +func TestRemoveAnnotation(t *testing.T) { + var o removeMetadataOptions + o.metadata = []string{"annotation1"} + + m := makeKustomization(t) + err := o.removeAnnotations(m) + if err != nil { + t.Errorf("unexpected error: could not write to kustomization file") + } + + // adding the same test input should not work + err = o.removeAnnotations(m) + if err == nil { + t.Errorf("expected not exist in kustomization file error") + } + + _, exists := m.CommonAnnotations["annotation1"] + if exists { + t.Errorf("annotation1 must be deleted") + } + + _, exists = m.CommonAnnotations["annotation2"] + if !exists { + t.Errorf("annotation2 must exist") + } +} + +func TestRemoveAnnotationIgnore(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + cmd.Flag("ignore-non-existence").Value.Set("true") + args := []string{"annotation3"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } +} + +func TestRemoveAnnotationNoDefinition(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteTestKustomizationWith([]byte("")) + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + args := []string{"annotation1,annotation2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "commonAnnotations is not defined in kustomization file" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveAnnotationNoDefinitionIgnore(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteTestKustomizationWith([]byte("")) + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + cmd.Flag("ignore-non-existence").Value.Set("true") + args := []string{"annotation1,annotation2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } +} + +func TestRemoveAnnotationNoArgs(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + err := cmd.Execute() + v.VerifyNoCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "must specify label" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveAnnotationInvalidFormat(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeSadMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + args := []string{"nospecialchars%^=@"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != validators.SAD { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveAnnotationMultipleArgs(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + args := []string{"annotation1,annotation2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } + + m := readKustomizationFS(t, fakeFS) + splitArgs := strings.Split(args[0], ",") + for _, k := range splitArgs { + if _, exist := m.CommonAnnotations[k]; exist { + t.Errorf("%s must be deleted", k) + } + } +} + +func TestRemoveAnnotationMultipleArgsInvalidFormat(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeSadMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + args := []string{"annotation1", "annotation2"} + err := cmd.RunE(cmd, args) + v.VerifyNoCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "labels must be comma-separated, with no spaces" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + func TestRemoveLabel(t *testing.T) { var o removeMetadataOptions o.metadata = []string{"label1"} diff --git a/pkg/ifc/ifc.go b/pkg/ifc/ifc.go index 9b17fefbc..550d488e9 100644 --- a/pkg/ifc/ifc.go +++ b/pkg/ifc/ifc.go @@ -12,6 +12,7 @@ import ( // Validator provides functions to validate annotations and labels type Validator interface { MakeAnnotationValidator() func(map[string]string) error + MakeAnnotationNameValidator() func([]string) error MakeLabelValidator() func(map[string]string) error MakeLabelNameValidator() func([]string) error ValidateNamespace(string) []string