diff --git a/api/v1alpha1/servicedefaults_types.go b/api/v1alpha1/servicedefaults_types.go index ff90b6b869..828bad2f37 100644 --- a/api/v1alpha1/servicedefaults_types.go +++ b/api/v1alpha1/servicedefaults_types.go @@ -1,7 +1,6 @@ package v1alpha1 import ( - "fmt" "strings" capi "github.com/hashicorp/consul/api" @@ -127,10 +126,12 @@ func (in *ServiceDefaults) ToConsul() capi.ConfigEntry { // returns an error which lists all invalid fields in the resource spec. func (in *ServiceDefaults) Validate() error { var allErrs field.ErrorList - if err := in.Spec.MeshGateway.validate(); err != nil { + path := field.NewPath("spec") + + if err := in.Spec.MeshGateway.validate(path.Child("meshGateway")); err != nil { allErrs = append(allErrs, err) } - allErrs = append(allErrs, in.Spec.Expose.validate()...) + allErrs = append(allErrs, in.Spec.Expose.validate(path.Child("expose"))...) if len(allErrs) > 0 { return apierrors.NewInvalid( @@ -226,15 +227,22 @@ func (e ExposeConfig) toConsul() capi.ExposeConfig { } } -func (e ExposeConfig) validate() []*field.Error { +func (e ExposeConfig) validate(path *field.Path) []*field.Error { var errs field.ErrorList protocols := []string{"http", "http2"} - for i, path := range e.Paths { - if path.Path != "" && !strings.HasPrefix(path.Path, "/") { - errs = append(errs, field.Invalid(field.NewPath("spec").Child("expose").Child(fmt.Sprintf("paths[%d]", i)).Child("path"), path.Path, `must begin with a '/'`)) + for i, pathCfg := range e.Paths { + indexPath := path.Child("paths").Index(i) + if pathCfg.Path != "" && !strings.HasPrefix(pathCfg.Path, "/") { + errs = append(errs, field.Invalid( + indexPath.Child("path"), + pathCfg.Path, + `must begin with a '/'`)) } - if !sliceContains(protocols, path.Protocol) { - errs = append(errs, field.Invalid(field.NewPath("spec").Child("expose").Child(fmt.Sprintf("paths[%d]", i)).Child("protocol"), path.Protocol, notInSliceMessage(protocols))) + if !sliceContains(protocols, pathCfg.Protocol) { + errs = append(errs, field.Invalid( + indexPath.Child("protocol"), + pathCfg.Protocol, + notInSliceMessage(protocols))) } } return errs diff --git a/api/v1alpha1/serviceresolver_types.go b/api/v1alpha1/serviceresolver_types.go index b8ba5bdd56..5ad9ef7355 100644 --- a/api/v1alpha1/serviceresolver_types.go +++ b/api/v1alpha1/serviceresolver_types.go @@ -1,7 +1,6 @@ package v1alpha1 import ( - "fmt" "reflect" "sort" "time" @@ -112,6 +111,7 @@ func (in *ServiceResolver) MatchesConsul(candidate capi.ConfigEntry) bool { func (in *ServiceResolver) Validate() error { var errs field.ErrorList + path := field.NewPath("spec") // Iterate through failover map keys in sorted order so tests are // deterministic. @@ -122,7 +122,7 @@ func (in *ServiceResolver) Validate() error { sort.Strings(keys) for _, k := range keys { f := in.Spec.Failover[k] - if err := f.validate(k); err != nil { + if err := f.validate(path.Child("failover").Key(k)); err != nil { errs = append(errs, err) } } @@ -132,9 +132,8 @@ func (in *ServiceResolver) Validate() error { in.Name(), errs) } -func (in *ServiceResolverFailover) validate(key string) *field.Error { +func (in *ServiceResolverFailover) validate(path *field.Path) *field.Error { if in.Service == "" && in.ServiceSubset == "" && in.Namespace == "" && len(in.Datacenters) == 0 { - path := field.NewPath("spec").Child(fmt.Sprintf("failover[%s]", key)) // NOTE: We're passing "{}" here as our value because we know that the // error is we have an empty object. return field.Invalid(path, "{}", diff --git a/api/v1alpha1/types.go b/api/v1alpha1/types.go index b5c5a165af..ad5bbfa854 100644 --- a/api/v1alpha1/types.go +++ b/api/v1alpha1/types.go @@ -52,10 +52,10 @@ func (m MeshGatewayConfig) toConsul() capi.MeshGatewayConfig { } } -func (m MeshGatewayConfig) validate() *field.Error { +func (m MeshGatewayConfig) validate(path *field.Path) *field.Error { modes := []string{"remote", "local", "none", ""} if !sliceContains(modes, m.Mode) { - return field.Invalid(field.NewPath("spec").Child("meshGateway").Child("mode"), m.Mode, notInSliceMessage(modes)) + return field.Invalid(path.Child("mode"), m.Mode, notInSliceMessage(modes)) } return nil }