Skip to content

Commit fa89a0a

Browse files
committed
Add validator interface
1 parent ad09355 commit fa89a0a

File tree

7 files changed

+132
-49
lines changed

7 files changed

+132
-49
lines changed

pkg/commands/addmetadata.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"sigs.k8s.io/kustomize/pkg/constants"
2525
"sigs.k8s.io/kustomize/pkg/fs"
2626
"sigs.k8s.io/kustomize/pkg/types"
27-
"sigs.k8s.io/kustomize/pkg/validators"
2827
)
2928

3029
// kindOfAdd is the kind of metadata being added: label or annotation
@@ -48,12 +47,12 @@ func (k kindOfAdd) String() string {
4847

4948
type addMetadataOptions struct {
5049
metadata map[string]string
51-
mapValidator validators.MapValidatorFunc
50+
mapValidator func(map[string]string) error
5251
kind kindOfAdd
5352
}
5453

5554
// newCmdAddAnnotation adds one or more commonAnnotations to the kustomization file.
56-
func newCmdAddAnnotation(fSys fs.FileSystem, v validators.MapValidatorFunc) *cobra.Command {
55+
func newCmdAddAnnotation(fSys fs.FileSystem, v func(map[string]string) error) *cobra.Command {
5756
var o addMetadataOptions
5857
o.kind = annotation
5958
o.mapValidator = v
@@ -70,7 +69,7 @@ func newCmdAddAnnotation(fSys fs.FileSystem, v validators.MapValidatorFunc) *cob
7069
}
7170

7271
// newCmdAddLabel adds one or more commonLabels to the kustomization file.
73-
func newCmdAddLabel(fSys fs.FileSystem, v validators.MapValidatorFunc) *cobra.Command {
72+
func newCmdAddLabel(fSys fs.FileSystem, v func(map[string]string) error) *cobra.Command {
7473
var o addMetadataOptions
7574
o.kind = label
7675
o.mapValidator = v

pkg/commands/commands.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424

2525
"github.com/spf13/cobra"
2626
"sigs.k8s.io/kustomize/pkg/fs"
27-
"sigs.k8s.io/kustomize/pkg/validators"
27+
"sigs.k8s.io/kustomize/pkg/ifc"
2828
)
2929

3030
// NewDefaultCommand returns the default (aka root) command for kustomize command.
@@ -45,7 +45,7 @@ See https://sigs.k8s.io/kustomize
4545
c.AddCommand(
4646
// TODO: Make consistent API for newCmd* functions.
4747
newCmdBuild(stdOut, fsys, k8sdeps.NewKustDecoder()),
48-
newCmdEdit(fsys),
48+
newCmdEdit(fsys, k8sdeps.NewKustValidator()),
4949
newCmdConfig(fsys),
5050
newCmdVersion(stdOut),
5151
)
@@ -58,7 +58,7 @@ See https://sigs.k8s.io/kustomize
5858
}
5959

6060
// newCmdEdit returns an instance of 'edit' subcommand.
61-
func newCmdEdit(fsys fs.FileSystem) *cobra.Command {
61+
func newCmdEdit(fsys fs.FileSystem, v ifc.Validator) *cobra.Command {
6262
c := &cobra.Command{
6363
Use: "edit",
6464
Short: "Edits a kustomization file",
@@ -73,14 +73,14 @@ func newCmdEdit(fsys fs.FileSystem) *cobra.Command {
7373
Args: cobra.MinimumNArgs(1),
7474
}
7575
c.AddCommand(
76-
newCmdAdd(fsys),
77-
newCmdSet(fsys),
76+
newCmdAdd(fsys, v),
77+
newCmdSet(fsys, v),
7878
)
7979
return c
8080
}
8181

8282
// newAddCommand returns an instance of 'add' subcommand.
83-
func newCmdAdd(fsys fs.FileSystem) *cobra.Command {
83+
func newCmdAdd(fsys fs.FileSystem, v ifc.Validator) *cobra.Command {
8484
c := &cobra.Command{
8585
Use: "add",
8686
Short: "Adds configmap/resource/patch/base to the kustomization file.",
@@ -112,14 +112,14 @@ func newCmdAdd(fsys fs.FileSystem) *cobra.Command {
112112
newCmdAddPatch(fsys),
113113
newCmdAddConfigMap(fsys),
114114
newCmdAddBase(fsys),
115-
newCmdAddLabel(fsys, validators.MakeLabelValidator()),
116-
newCmdAddAnnotation(fsys, validators.MakeAnnotationValidator()),
115+
newCmdAddLabel(fsys, v.MakeLabelValidator()),
116+
newCmdAddAnnotation(fsys, v.MakeAnnotationValidator()),
117117
)
118118
return c
119119
}
120120

121121
// newSetCommand returns an instance of 'set' subcommand.
122-
func newCmdSet(fsys fs.FileSystem) *cobra.Command {
122+
func newCmdSet(fsys fs.FileSystem, v ifc.Validator) *cobra.Command {
123123
c := &cobra.Command{
124124
Use: "set",
125125
Short: "Sets the value of different fields in kustomization file.",
@@ -133,7 +133,7 @@ func newCmdSet(fsys fs.FileSystem) *cobra.Command {
133133

134134
c.AddCommand(
135135
newCmdSetNamePrefix(fsys),
136-
newCmdSetNamespace(fsys),
136+
newCmdSetNamespace(fsys, v),
137137
newCmdSetImageTag(fsys),
138138
)
139139
return c

pkg/commands/setnamespace.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,18 @@ import (
2222
"strings"
2323

2424
"github.com/spf13/cobra"
25-
"k8s.io/apimachinery/pkg/util/validation"
2625
"sigs.k8s.io/kustomize/pkg/constants"
2726
"sigs.k8s.io/kustomize/pkg/fs"
27+
"sigs.k8s.io/kustomize/pkg/ifc"
2828
)
2929

3030
type setNamespaceOptions struct {
3131
namespace string
32+
validator ifc.Validator
3233
}
3334

3435
// newCmdSetNamespace sets the value of the namespace field in the kustomization.
35-
func newCmdSetNamespace(fsys fs.FileSystem) *cobra.Command {
36+
func newCmdSetNamespace(fsys fs.FileSystem, v ifc.Validator) *cobra.Command {
3637
var o setNamespaceOptions
3738

3839
cmd := &cobra.Command{
@@ -45,6 +46,7 @@ will add the field "namespace: staging" to the kustomization file if it doesn't
4546
and overwrite the value with "staging" if the field does exist.
4647
`,
4748
RunE: func(cmd *cobra.Command, args []string) error {
49+
o.validator = v
4850
err := o.Validate(args)
4951
if err != nil {
5052
return err
@@ -61,7 +63,7 @@ func (o *setNamespaceOptions) Validate(args []string) error {
6163
return errors.New("must specify exactly one namespace value")
6264
}
6365
ns := args[0]
64-
if errs := validation.IsDNS1123Label(ns); len(errs) != 0 {
66+
if errs := o.validator.ValidateNamespace(ns); len(errs) != 0 {
6567
return fmt.Errorf("%q is not a valid namespace name: %s", ns, strings.Join(errs, ";"))
6668
}
6769
o.namespace = ns

pkg/commands/setnamespace_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"sigs.k8s.io/kustomize/pkg/constants"
2525
"sigs.k8s.io/kustomize/pkg/fs"
26+
"sigs.k8s.io/kustomize/pkg/validators"
2627
)
2728

2829
const (
@@ -33,7 +34,7 @@ func TestSetNamespaceHappyPath(t *testing.T) {
3334
fakeFS := fs.MakeFakeFS()
3435
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
3536

36-
cmd := newCmdSetNamespace(fakeFS)
37+
cmd := newCmdSetNamespace(fakeFS, validators.MakeFakeValidator())
3738
args := []string{goodNamespaceValue}
3839
err := cmd.RunE(cmd, args)
3940
if err != nil {
@@ -53,7 +54,7 @@ func TestSetNamespaceOverride(t *testing.T) {
5354
fakeFS := fs.MakeFakeFS()
5455
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
5556

56-
cmd := newCmdSetNamespace(fakeFS)
57+
cmd := newCmdSetNamespace(fakeFS, validators.MakeFakeValidator())
5758
args := []string{goodNamespaceValue}
5859
err := cmd.RunE(cmd, args)
5960
if err != nil {
@@ -77,7 +78,7 @@ func TestSetNamespaceOverride(t *testing.T) {
7778
func TestSetNamespaceNoArgs(t *testing.T) {
7879
fakeFS := fs.MakeFakeFS()
7980

80-
cmd := newCmdSetNamespace(fakeFS)
81+
cmd := newCmdSetNamespace(fakeFS, validators.MakeFakeValidator())
8182
err := cmd.Execute()
8283
if err == nil {
8384
t.Errorf("expected error: %v", err)
@@ -91,7 +92,7 @@ func TestSetNamespaceInvalid(t *testing.T) {
9192
fakeFS := fs.MakeFakeFS()
9293
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
9394

94-
cmd := newCmdSetNamespace(fakeFS)
95+
cmd := newCmdSetNamespace(fakeFS, validators.MakeFakeValidator())
9596
args := []string{"/badnamespace/"}
9697
err := cmd.RunE(cmd, args)
9798
if err == nil {

pkg/ifc/ifc.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,10 @@ type Decoder interface {
2424
// Decode yields the next object from the input, else io.EOF
2525
Decode(interface{}) error
2626
}
27+
28+
// Validator provides functions to validate annotations and labels
29+
type Validator interface {
30+
MakeAnnotationValidator() func(map[string]string) error
31+
MakeLabelValidator() func(map[string]string) error
32+
ValidateNamespace(string) []string
33+
}

pkg/internal/k8sdeps/validators.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package k8sdeps
18+
19+
import (
20+
"errors"
21+
apivalidation "k8s.io/apimachinery/pkg/api/validation"
22+
v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
23+
"k8s.io/apimachinery/pkg/util/validation"
24+
"k8s.io/apimachinery/pkg/util/validation/field"
25+
)
26+
27+
// KustValidator validates Labels and annotations by apimachinery
28+
type KustValidator struct{}
29+
30+
// NewKustValidator returns a KustValidator object
31+
func NewKustValidator() *KustValidator {
32+
return &KustValidator{}
33+
}
34+
35+
// MakeAnnotationValidator returns a MapValidatorFunc using apimachinery.
36+
func (v *KustValidator) MakeAnnotationValidator() func(map[string]string) error {
37+
return func(x map[string]string) error {
38+
errs := apivalidation.ValidateAnnotations(x, field.NewPath("field"))
39+
if errs != nil {
40+
return errors.New(errs.ToAggregate().Error())
41+
}
42+
return nil
43+
}
44+
}
45+
46+
// MakeLabelValidator returns a MapValidatorFunc using apimachinery.
47+
func (v *KustValidator) MakeLabelValidator() func(map[string]string) error {
48+
return func(x map[string]string) error {
49+
errs := v1validation.ValidateLabels(x, field.NewPath("field"))
50+
if errs != nil {
51+
return errors.New(errs.ToAggregate().Error())
52+
}
53+
return nil
54+
}
55+
}
56+
57+
// ValidateNamespace validates a string is a valid namespace using apimachinery.
58+
func (v *KustValidator) ValidateNamespace(s string) []string {
59+
return validation.IsDNS1123Label(s)
60+
}

pkg/validators/validators.go

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,28 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// Package validators defines a FakeValidator that can be used in tests
118
package validators
219

320
import (
421
"errors"
5-
apivalidation "k8s.io/apimachinery/pkg/api/validation"
6-
v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
7-
"k8s.io/apimachinery/pkg/util/validation/field"
22+
"regexp"
823
"testing"
924
)
1025

11-
// MapValidatorFunc returns an error if a map contains errors.
12-
type MapValidatorFunc func(map[string]string) error
13-
14-
// MakeAnnotationValidator returns a MapValidatorFunc using apimachinery.
15-
func MakeAnnotationValidator() MapValidatorFunc {
16-
return func(x map[string]string) error {
17-
errs := apivalidation.ValidateAnnotations(x, field.NewPath("field"))
18-
if len(errs) > 0 {
19-
return errors.New(errs.ToAggregate().Error())
20-
}
21-
return nil
22-
}
23-
}
24-
25-
// MakeLabelValidator returns a MapValidatorFunc using apimachinery.
26-
func MakeLabelValidator() MapValidatorFunc {
27-
return func(x map[string]string) error {
28-
errs := v1validation.ValidateLabels(x, field.NewPath("field"))
29-
if len(errs) > 0 {
30-
return errors.New(errs.ToAggregate().Error())
31-
}
32-
return nil
33-
}
34-
}
35-
3626
// FakeValidator can be used in tests.
3727
type FakeValidator struct {
3828
happy bool
@@ -53,6 +43,30 @@ func MakeSadMapValidator(t *testing.T) *FakeValidator {
5343
return &FakeValidator{happy: false, t: t}
5444
}
5545

46+
// MakeFakeValidator makes an empty Fake Validator.
47+
func MakeFakeValidator() *FakeValidator {
48+
return &FakeValidator{}
49+
}
50+
51+
// MakeAnnotationValidator returns a nil function
52+
func (v *FakeValidator) MakeAnnotationValidator() func(map[string]string) error {
53+
return nil
54+
}
55+
56+
// MakeLabelValidator returns a nil function
57+
func (v *FakeValidator) MakeLabelValidator() func(map[string]string) error {
58+
return nil
59+
}
60+
61+
// ValidateNamespace validates namespace by regexp
62+
func (v *FakeValidator) ValidateNamespace(s string) []string {
63+
pattern := regexp.MustCompile(`^[a-zA-Z].*`)
64+
if pattern.MatchString(s) {
65+
return nil
66+
}
67+
return []string{"doesn't match"}
68+
}
69+
5670
// Validator replaces apimachinery validation in tests.
5771
// Can be set to fail or succeed to test error handling.
5872
// Can confirm if run or not run by surrounding code.

0 commit comments

Comments
 (0)