diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index 6051c4664b..a2d1fd2da9 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -270,6 +270,8 @@ func (in *IngressGateway) Validate(consulMeta common.ConsulMeta) error { errs = append(errs, v.validate(path.Child("listeners").Index(i), consulMeta)...) } + errs = append(errs, in.Spec.Defaults.validate(path.Child("defaults"))...) + if len(errs) > 0 { return apierrors.NewInvalid( schema.GroupKind{Group: ConsulHashicorpGroup, Kind: ingressGatewayKubeKind}, @@ -419,6 +421,38 @@ func (in IngressListener) validate(path *field.Path, consulMeta common.ConsulMet string(asJSON), "hosts must be empty if protocol is \"tcp\"")) } + + if svc.MaxConnections != nil && *svc.MaxConnections <= 0 { + errs = append(errs, field.Invalid(path.Child("maxconnections"), *svc.MaxConnections, "MaxConnections must be > 0")) + } + + if svc.MaxConcurrentRequests != nil && *svc.MaxConcurrentRequests <= 0 { + errs = append(errs, field.Invalid(path.Child("maxconcurrentrequests"), *svc.MaxConcurrentRequests, "MaxConcurrentRequests must be > 0")) + } + + if svc.MaxPendingRequests != nil && *svc.MaxPendingRequests <= 0 { + errs = append(errs, field.Invalid(path.Child("maxpendingrequests"), *svc.MaxPendingRequests, "MaxPendingRequests must be > 0")) + } + } + return errs +} + +func (in *IngressServiceConfig) validate(path *field.Path) field.ErrorList { + if in == nil { + return nil + } + var errs field.ErrorList + + if in.MaxConnections != nil && *in.MaxConnections <= 0 { + errs = append(errs, field.Invalid(path.Child("maxconnections"), *in.MaxConnections, "MaxConnections must be > 0")) + } + + if in.MaxConcurrentRequests != nil && *in.MaxConcurrentRequests <= 0 { + errs = append(errs, field.Invalid(path.Child("maxconcurrentrequests"), *in.MaxConcurrentRequests, "MaxConcurrentRequests must be > 0")) + } + + if in.MaxPendingRequests != nil && *in.MaxPendingRequests <= 0 { + errs = append(errs, field.Invalid(path.Child("maxpendingrequests"), *in.MaxPendingRequests, "MaxPendingRequests must be > 0")) } return errs } diff --git a/control-plane/api/v1alpha1/ingressgateway_types_test.go b/control-plane/api/v1alpha1/ingressgateway_types_test.go index 2585614519..6d70f23c5f 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types_test.go +++ b/control-plane/api/v1alpha1/ingressgateway_types_test.go @@ -471,6 +471,8 @@ func TestIngressGateway_ToConsul(t *testing.T) { } func TestIngressGateway_Validate(t *testing.T) { + zero := uint32(0) + cases := map[string]struct { input *IngressGateway namespacesEnabled bool @@ -785,6 +787,121 @@ func TestIngressGateway_Validate(t *testing.T) { }, partitionEnabled: true, }, + "defaults.maxConnections invalid": { + input: &IngressGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: IngressGatewaySpec{ + Defaults: &IngressServiceConfig{ + MaxConnections: &zero, + }, + }, + }, + expectedErrMsgs: []string{ + `spec.defaults.maxconnections: Invalid`, + }, + }, + "defaults.maxPendingRequests invalid": { + input: &IngressGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: IngressGatewaySpec{ + Defaults: &IngressServiceConfig{ + MaxPendingRequests: &zero, + }, + }, + }, + expectedErrMsgs: []string{ + `spec.defaults.maxpendingrequests: Invalid`, + }, + }, + "defaults.maxConcurrentRequests invalid": { + input: &IngressGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: IngressGatewaySpec{ + Defaults: &IngressServiceConfig{ + MaxConcurrentRequests: &zero, + }, + }, + }, + expectedErrMsgs: []string{ + `spec.defaults.maxconcurrentrequests: Invalid`, + }, + }, + "service.maxConnections invalid": { + input: &IngressGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: IngressGatewaySpec{ + Listeners: []IngressListener{ + { + Protocol: "http", + Services: []IngressService{ + { + Name: "svc1", + MaxConnections: &zero, + }, + }, + }, + }, + }, + }, + expectedErrMsgs: []string{ + `spec.listeners[0].maxconnections: Invalid`, + }, + }, + "service.maxConcurrentRequests invalid": { + input: &IngressGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: IngressGatewaySpec{ + Listeners: []IngressListener{ + { + Protocol: "http", + Services: []IngressService{ + { + Name: "svc1", + MaxConcurrentRequests: &zero, + }, + }, + }, + }, + }, + }, + expectedErrMsgs: []string{ + `spec.listeners[0].maxconcurrentrequests: Invalid`, + }, + }, + "service.maxPendingRequests invalid": { + input: &IngressGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: IngressGatewaySpec{ + Listeners: []IngressListener{ + { + Protocol: "http", + Services: []IngressService{ + { + Name: "svc1", + MaxPendingRequests: &zero, + }, + }, + }, + }, + }, + }, + expectedErrMsgs: []string{ + `spec.listeners[0].maxpendingrequests: Invalid`, + }, + }, + "multiple errors": { input: &IngressGateway{ ObjectMeta: metav1.ObjectMeta{