diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ce8d8aca5..71c37d205a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ ## UNRELEASED +FEATURES: +* Ingress Gateway + * Add support for MaxConnections, MaxConcurrentRequests, and MaxPendingRequests to Ingress Gateway CRD. [[GH-1691](https://github.com/hashicorp/consul-k8s/pull/1691)] IMPROVEMENTS: * Helm: diff --git a/charts/consul/templates/crd-ingressgateways.yaml b/charts/consul/templates/crd-ingressgateways.yaml index 1a241a9cfb..6aeca4a2f7 100644 --- a/charts/consul/templates/crd-ingressgateways.yaml +++ b/charts/consul/templates/crd-ingressgateways.yaml @@ -61,12 +61,21 @@ spec: description: Defaults is default configuration for all upstream services properties: maxConcurrentRequests: + description: The maximum number of concurrent requests that will + be allowed at a single point in time. Use this to limit HTTP/2 + traffic, since HTTP/2 has many requests per connection. format: int32 type: integer maxConnections: + description: The maximum number of connections a service instance + will be allowed to establish against the given upstream. Use + this to limit HTTP/1.1 traffic, since HTTP/1.1 has a request + per connection. format: int32 type: integer maxPendingRequests: + description: The maximum number of requests that will be queued + while waiting for a connection to be established. format: int32 type: integer type: object @@ -112,12 +121,22 @@ spec: type: string type: array maxConcurrentRequests: + description: The maximum number of concurrent requests + that will be allowed at a single point in time. Use + this to limit HTTP/2 traffic, since HTTP/2 has many + requests per connection. format: int32 type: integer maxConnections: + description: The maximum number of connections a service + instance will be allowed to establish against the given + upstream. Use this to limit HTTP/1.1 traffic, since + HTTP/1.1 has a request per connection. format: int32 type: integer maxPendingRequests: + description: The maximum number of requests that will + be queued while waiting for a connection to be established. format: int32 type: integer name: diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index d213b7eb84..c94b6e1458 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -63,8 +63,16 @@ type IngressGatewaySpec struct { } type IngressServiceConfig struct { - MaxConnections *uint32 `json:"maxConnections,omitempty"` - MaxPendingRequests *uint32 `json:"maxPendingRequests,omitempty"` + // The maximum number of connections a service instance + // will be allowed to establish against the given upstream. Use this to limit + // HTTP/1.1 traffic, since HTTP/1.1 has a request per connection. + MaxConnections *uint32 `json:"maxConnections,omitempty"` + // The maximum number of requests that will be queued + // while waiting for a connection to be established. + MaxPendingRequests *uint32 `json:"maxPendingRequests,omitempty"` + // The maximum number of concurrent requests that + // will be allowed at a single point in time. Use this to limit HTTP/2 traffic, + // since HTTP/2 has many requests per connection. MaxConcurrentRequests *uint32 `json:"maxConcurrentRequests,omitempty"` } @@ -154,9 +162,7 @@ type IngressService struct { RequestHeaders *HTTPHeaderModifiers `json:"requestHeaders,omitempty"` ResponseHeaders *HTTPHeaderModifiers `json:"responseHeaders,omitempty"` - MaxConnections *uint32 `json:"maxConnections,omitempty"` - MaxPendingRequests *uint32 `json:"maxPendingRequests,omitempty"` - MaxConcurrentRequests *uint32 `json:"maxConcurrentRequests,omitempty"` + IngressServiceConfig `json:",inline"` } func (in *IngressGateway) GetObjectMeta() metav1.ObjectMeta { @@ -426,17 +432,7 @@ func (in IngressListener) validate(path *field.Path, consulMeta common.ConsulMet "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")) - } + errs = append(errs, svc.IngressServiceConfig.validate(path)...) } return errs } diff --git a/control-plane/api/v1alpha1/ingressgateway_types_test.go b/control-plane/api/v1alpha1/ingressgateway_types_test.go index c60f487954..4942d38e11 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types_test.go +++ b/control-plane/api/v1alpha1/ingressgateway_types_test.go @@ -13,6 +13,15 @@ import ( ) func TestIngressGateway_MatchesConsul(t *testing.T) { + + defaultMaxConnections := uint32(100) + defaultMaxPendingRequests := uint32(101) + defaultMaxConcurrentRequests := uint32(102) + + maxConnections := uint32(200) + maxPendingRequests := uint32(201) + maxConcurrentRequests := uint32(202) + cases := map[string]struct { Ours IngressGateway Theirs capi.ConfigEntry @@ -54,6 +63,11 @@ func TestIngressGateway_MatchesConsul(t *testing.T) { TLSMaxVersion: "TLSv1_1", CipherSuites: []string{"ECDHE-ECDSA-AES128-GCM-SHA256", "AES128-SHA"}, }, + Defaults: &IngressServiceConfig{ + MaxConnections: &defaultMaxConnections, + MaxPendingRequests: &defaultMaxPendingRequests, + MaxConcurrentRequests: &defaultMaxConcurrentRequests, + }, Listeners: []IngressListener{ { Port: 8888, @@ -74,6 +88,11 @@ func TestIngressGateway_MatchesConsul(t *testing.T) { Hosts: []string{"host1_1", "host1_2"}, Namespace: "ns1", Partition: "default", + IngressServiceConfig: IngressServiceConfig{ + MaxConnections: &maxConnections, + MaxPendingRequests: &maxPendingRequests, + MaxConcurrentRequests: &maxConcurrentRequests, + }, TLS: &GatewayServiceTLSConfig{ SDS: &GatewayTLSSDSConfig{ ClusterName: "cluster1", @@ -144,6 +163,11 @@ func TestIngressGateway_MatchesConsul(t *testing.T) { TLSMaxVersion: "TLSv1_1", CipherSuites: []string{"ECDHE-ECDSA-AES128-GCM-SHA256", "AES128-SHA"}, }, + Defaults: &capi.IngressServiceConfig{ + MaxConnections: &defaultMaxConnections, + MaxPendingRequests: &defaultMaxPendingRequests, + MaxConcurrentRequests: &defaultMaxConcurrentRequests, + }, Listeners: []capi.IngressListener{ { Port: 8888, @@ -160,10 +184,13 @@ func TestIngressGateway_MatchesConsul(t *testing.T) { }, Services: []capi.IngressService{ { - Name: "name1", - Hosts: []string{"host1_1", "host1_2"}, - Namespace: "ns1", - Partition: "default", + Name: "name1", + Hosts: []string{"host1_1", "host1_2"}, + Namespace: "ns1", + Partition: "default", + MaxConnections: &maxConnections, + MaxPendingRequests: &maxPendingRequests, + MaxConcurrentRequests: &maxConcurrentRequests, TLS: &capi.GatewayServiceTLSConfig{ SDS: &capi.GatewayTLSSDSConfig{ ClusterName: "cluster1", @@ -319,13 +346,15 @@ func TestIngressGateway_ToConsul(t *testing.T) { }, Services: []IngressService{ { - Name: "name1", - Hosts: []string{"host1_1", "host1_2"}, - Namespace: "ns1", - Partition: "default", - MaxConnections: &maxConnections, - MaxPendingRequests: &maxPendingRequests, - MaxConcurrentRequests: &maxConcurrentRequests, + Name: "name1", + Hosts: []string{"host1_1", "host1_2"}, + Namespace: "ns1", + Partition: "default", + IngressServiceConfig: IngressServiceConfig{ + MaxConnections: &maxConnections, + MaxPendingRequests: &maxPendingRequests, + MaxConcurrentRequests: &maxConcurrentRequests, + }, TLS: &GatewayServiceTLSConfig{ SDS: &GatewayTLSSDSConfig{ ClusterName: "cluster1", @@ -868,8 +897,10 @@ func TestIngressGateway_Validate(t *testing.T) { Protocol: "http", Services: []IngressService{ { - Name: "svc1", - MaxConnections: &zero, + Name: "svc1", + IngressServiceConfig: IngressServiceConfig{ + MaxConnections: &zero, + }, }, }, }, @@ -891,8 +922,10 @@ func TestIngressGateway_Validate(t *testing.T) { Protocol: "http", Services: []IngressService{ { - Name: "svc1", - MaxConcurrentRequests: &zero, + Name: "svc1", + IngressServiceConfig: IngressServiceConfig{ + MaxConcurrentRequests: &zero, + }, }, }, }, @@ -914,8 +947,10 @@ func TestIngressGateway_Validate(t *testing.T) { Protocol: "http", Services: []IngressService{ { - Name: "svc1", - MaxPendingRequests: &zero, + Name: "svc1", + IngressServiceConfig: IngressServiceConfig{ + MaxPendingRequests: &zero, + }, }, }, }, diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index af7ec840a1..cacef8c64c 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -450,21 +450,7 @@ func (in *IngressService) DeepCopyInto(out *IngressService) { *out = new(HTTPHeaderModifiers) (*in).DeepCopyInto(*out) } - if in.MaxConnections != nil { - in, out := &in.MaxConnections, &out.MaxConnections - *out = new(uint32) - **out = **in - } - if in.MaxPendingRequests != nil { - in, out := &in.MaxPendingRequests, &out.MaxPendingRequests - *out = new(uint32) - **out = **in - } - if in.MaxConcurrentRequests != nil { - in, out := &in.MaxConcurrentRequests, &out.MaxConcurrentRequests - *out = new(uint32) - **out = **in - } + in.IngressServiceConfig.DeepCopyInto(&out.IngressServiceConfig) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressService. diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml index 9934e9c0d9..16ac322090 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml @@ -54,12 +54,21 @@ spec: description: Defaults is default configuration for all upstream services properties: maxConcurrentRequests: + description: The maximum number of concurrent requests that will + be allowed at a single point in time. Use this to limit HTTP/2 + traffic, since HTTP/2 has many requests per connection. format: int32 type: integer maxConnections: + description: The maximum number of connections a service instance + will be allowed to establish against the given upstream. Use + this to limit HTTP/1.1 traffic, since HTTP/1.1 has a request + per connection. format: int32 type: integer maxPendingRequests: + description: The maximum number of requests that will be queued + while waiting for a connection to be established. format: int32 type: integer type: object @@ -105,12 +114,22 @@ spec: type: string type: array maxConcurrentRequests: + description: The maximum number of concurrent requests + that will be allowed at a single point in time. Use + this to limit HTTP/2 traffic, since HTTP/2 has many + requests per connection. format: int32 type: integer maxConnections: + description: The maximum number of connections a service + instance will be allowed to establish against the given + upstream. Use this to limit HTTP/1.1 traffic, since + HTTP/1.1 has a request per connection. format: int32 type: integer maxPendingRequests: + description: The maximum number of requests that will + be queued while waiting for a connection to be established. format: int32 type: integer name: