From 54acfb4cd16ee980e4fad14462b366943a0ace7b Mon Sep 17 00:00:00 2001
From: Kate Osborn <50597707+kate-osborn@users.noreply.github.com>
Date: Tue, 28 Jan 2025 12:24:18 -0700
Subject: [PATCH] Support NginxProxy at the Gateway level (#3058)
Problem: When the control plane and data planes are split, the user will need the ability to specify data plane settings on a per-Gateway basis. To allow this, we need to support NginxProxy at the Gateway level in addition the the GatewayClass level. In practice, this means a user can reference an NginxProxy resource via the
spec.infrastructure.parametersRef field on the Gateway resource. We still want to support referencing an NginxProxy at the GatewayClass level. If a Gateway and its GatewayClass reference distinct NginxProxy resources, the settings must be merged. Settings specified on a Gateway NginxProxy must override those set on the GatewayClass NginxProxy.
Solution: To support NginxProxy at the Gateway level several changes were made to the API.
As a result, the API is now at version v1alpha2.
Breaking Changes:
* Change the scope of the CRD to Namespaced. The parametersRef.namespace field on the GatewayClass is now required.
* Make DisableHTTP2 and Telemetry.Exporter.Endpoint optional.
New fields:
* Telemetry.DisabledFeatures: allows users to explicitly disable telemetry features. It is a list with one supported entry: DisableTracing. More features may be added in future releases.
Other changes:
* Remove the listType=Map kubebuilder annotation from the RewriteClientIP.TrustedAddresses field. This listType is incorrect since TrustedAddresses can have duplicate keys.
The graph now stores NginxProxies that are referenced by the winning GatewayClass and Gateway. This will need to be updated once we support multiple Gateways. The graph is also responsible for merging the NginxProxies when necessary. The result of this is stored on the graph's Gateway object in the field EffectiveNginxProxy. The EffectiveNginxProxy on the Gateway is used to build the NGINX configuration.
---
apis/v1alpha1/register.go | 2 -
apis/v1alpha1/zz_generated.deepcopy.go | 218 ---
apis/v1alpha2/doc.go | 6 +
.../nginxproxy_types.go | 46 +-
apis/v1alpha2/register.go | 41 +
apis/v1alpha2/zz_generated.deepcopy.go | 243 +++
.../templates/gatewayclass.yaml | 1 +
.../templates/nginxproxy.yaml | 3 +-
.../nginx-gateway-fabric/values.schema.json | 11 +
charts/nginx-gateway-fabric/values.yaml | 6 +
.../bases/gateway.nginx.org_nginxproxies.yaml | 30 +-
deploy/crds.yaml | 30 +-
internal/mode/static/manager.go | 36 +-
internal/mode/static/manager_test.go | 47 +-
.../mode/static/state/change_processor.go | 17 +-
.../static/state/change_processor_test.go | 243 ++-
.../static/state/conditions/conditions.go | 81 +-
.../static/state/dataplane/configuration.go | 93 +-
.../state/dataplane/configuration_test.go | 586 ++++---
.../mode/static/state/graph/backend_refs.go | 51 +-
.../static/state/graph/backend_refs_test.go | 51 +-
internal/mode/static/state/graph/gateway.go | 101 +-
.../mode/static/state/graph/gateway_test.go | 356 ++++-
.../mode/static/state/graph/gatewayclass.go | 106 +-
.../static/state/graph/gatewayclass_test.go | 136 +-
internal/mode/static/state/graph/graph.go | 78 +-
.../mode/static/state/graph/graph_test.go | 183 ++-
.../mode/static/state/graph/grpcroute_test.go | 34 +-
.../mode/static/state/graph/nginxproxy.go | 220 ++-
.../static/state/graph/nginxproxy_test.go | 952 ++++++++---
.../mode/static/state/graph/route_common.go | 15 +-
internal/mode/static/state/graph/tlsroute.go | 4 +-
.../mode/static/state/graph/tlsroute_test.go | 11 +-
.../mode/static/status/prepare_requests.go | 2 +
.../static/status/prepare_requests_test.go | 111 ++
internal/mode/static/telemetry/collector.go | 5 +-
.../mode/static/telemetry/collector_test.go | 15 +-
.../how-to/data-plane-configuration.md | 6 +-
site/content/reference/api.md | 1393 +++++++++--------
tests/suite/manifests/tracing/nginxproxy.yaml | 2 +-
40 files changed, 3592 insertions(+), 1980 deletions(-)
create mode 100644 apis/v1alpha2/doc.go
rename apis/{v1alpha1 => v1alpha2}/nginxproxy_types.go (86%)
create mode 100644 apis/v1alpha2/register.go
create mode 100644 apis/v1alpha2/zz_generated.deepcopy.go
diff --git a/apis/v1alpha1/register.go b/apis/v1alpha1/register.go
index 0d18c29eaa..7deb5bfb5c 100644
--- a/apis/v1alpha1/register.go
+++ b/apis/v1alpha1/register.go
@@ -34,8 +34,6 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&NginxGateway{},
&NginxGatewayList{},
- &NginxProxy{},
- &NginxProxyList{},
&ObservabilityPolicy{},
&ObservabilityPolicyList{},
&ClientSettingsPolicy{},
diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go
index 9624b658aa..a70a3d38a6 100644
--- a/apis/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/v1alpha1/zz_generated.deepcopy.go
@@ -10,21 +10,6 @@ import (
"sigs.k8s.io/gateway-api/apis/v1alpha2"
)
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Address) DeepCopyInto(out *Address) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Address.
-func (in *Address) DeepCopy() *Address {
- if in == nil {
- return nil
- }
- out := new(Address)
- in.DeepCopyInto(out)
- return out
-}
-
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClientBody) DeepCopyInto(out *ClientBody) {
*out = *in
@@ -333,119 +318,6 @@ func (in *NginxGatewayStatus) DeepCopy() *NginxGatewayStatus {
return out
}
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *NginxLogging) DeepCopyInto(out *NginxLogging) {
- *out = *in
- if in.ErrorLevel != nil {
- in, out := &in.ErrorLevel, &out.ErrorLevel
- *out = new(NginxErrorLogLevel)
- **out = **in
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NginxLogging.
-func (in *NginxLogging) DeepCopy() *NginxLogging {
- if in == nil {
- return nil
- }
- out := new(NginxLogging)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *NginxProxy) DeepCopyInto(out *NginxProxy) {
- *out = *in
- out.TypeMeta = in.TypeMeta
- in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
- in.Spec.DeepCopyInto(&out.Spec)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NginxProxy.
-func (in *NginxProxy) DeepCopy() *NginxProxy {
- if in == nil {
- return nil
- }
- out := new(NginxProxy)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *NginxProxy) DeepCopyObject() runtime.Object {
- if c := in.DeepCopy(); c != nil {
- return c
- }
- return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *NginxProxyList) DeepCopyInto(out *NginxProxyList) {
- *out = *in
- out.TypeMeta = in.TypeMeta
- in.ListMeta.DeepCopyInto(&out.ListMeta)
- if in.Items != nil {
- in, out := &in.Items, &out.Items
- *out = make([]NginxProxy, len(*in))
- for i := range *in {
- (*in)[i].DeepCopyInto(&(*out)[i])
- }
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NginxProxyList.
-func (in *NginxProxyList) DeepCopy() *NginxProxyList {
- if in == nil {
- return nil
- }
- out := new(NginxProxyList)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *NginxProxyList) DeepCopyObject() runtime.Object {
- if c := in.DeepCopy(); c != nil {
- return c
- }
- return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *NginxProxySpec) DeepCopyInto(out *NginxProxySpec) {
- *out = *in
- if in.IPFamily != nil {
- in, out := &in.IPFamily, &out.IPFamily
- *out = new(IPFamilyType)
- **out = **in
- }
- if in.Telemetry != nil {
- in, out := &in.Telemetry, &out.Telemetry
- *out = new(Telemetry)
- (*in).DeepCopyInto(*out)
- }
- if in.RewriteClientIP != nil {
- in, out := &in.RewriteClientIP, &out.RewriteClientIP
- *out = new(RewriteClientIP)
- (*in).DeepCopyInto(*out)
- }
- if in.Logging != nil {
- in, out := &in.Logging, &out.Logging
- *out = new(NginxLogging)
- (*in).DeepCopyInto(*out)
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NginxProxySpec.
-func (in *NginxProxySpec) DeepCopy() *NginxProxySpec {
- if in == nil {
- return nil
- }
- out := new(NginxProxySpec)
- in.DeepCopyInto(out)
- return out
-}
-
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObservabilityPolicy) DeepCopyInto(out *ObservabilityPolicy) {
*out = *in
@@ -530,36 +402,6 @@ func (in *ObservabilityPolicySpec) DeepCopy() *ObservabilityPolicySpec {
return out
}
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *RewriteClientIP) DeepCopyInto(out *RewriteClientIP) {
- *out = *in
- if in.Mode != nil {
- in, out := &in.Mode, &out.Mode
- *out = new(RewriteClientIPModeType)
- **out = **in
- }
- if in.SetIPRecursively != nil {
- in, out := &in.SetIPRecursively, &out.SetIPRecursively
- *out = new(bool)
- **out = **in
- }
- if in.TrustedAddresses != nil {
- in, out := &in.TrustedAddresses, &out.TrustedAddresses
- *out = make([]Address, len(*in))
- copy(*out, *in)
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RewriteClientIP.
-func (in *RewriteClientIP) DeepCopy() *RewriteClientIP {
- if in == nil {
- return nil
- }
- out := new(RewriteClientIP)
- in.DeepCopyInto(out)
- return out
-}
-
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Snippet) DeepCopyInto(out *Snippet) {
*out = *in
@@ -691,66 +533,6 @@ func (in *SpanAttribute) DeepCopy() *SpanAttribute {
return out
}
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Telemetry) DeepCopyInto(out *Telemetry) {
- *out = *in
- if in.Exporter != nil {
- in, out := &in.Exporter, &out.Exporter
- *out = new(TelemetryExporter)
- (*in).DeepCopyInto(*out)
- }
- if in.ServiceName != nil {
- in, out := &in.ServiceName, &out.ServiceName
- *out = new(string)
- **out = **in
- }
- if in.SpanAttributes != nil {
- in, out := &in.SpanAttributes, &out.SpanAttributes
- *out = make([]SpanAttribute, len(*in))
- copy(*out, *in)
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Telemetry.
-func (in *Telemetry) DeepCopy() *Telemetry {
- if in == nil {
- return nil
- }
- out := new(Telemetry)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TelemetryExporter) DeepCopyInto(out *TelemetryExporter) {
- *out = *in
- if in.Interval != nil {
- in, out := &in.Interval, &out.Interval
- *out = new(Duration)
- **out = **in
- }
- if in.BatchSize != nil {
- in, out := &in.BatchSize, &out.BatchSize
- *out = new(int32)
- **out = **in
- }
- if in.BatchCount != nil {
- in, out := &in.BatchCount, &out.BatchCount
- *out = new(int32)
- **out = **in
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TelemetryExporter.
-func (in *TelemetryExporter) DeepCopy() *TelemetryExporter {
- if in == nil {
- return nil
- }
- out := new(TelemetryExporter)
- in.DeepCopyInto(out)
- return out
-}
-
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Tracing) DeepCopyInto(out *Tracing) {
*out = *in
diff --git a/apis/v1alpha2/doc.go b/apis/v1alpha2/doc.go
new file mode 100644
index 0000000000..6e93a89ac7
--- /dev/null
+++ b/apis/v1alpha2/doc.go
@@ -0,0 +1,6 @@
+// Package v1alpha2 contains API Schema definitions for the
+// gateway.nginx.org API group.
+//
+// +kubebuilder:object:generate=true
+// +groupName=gateway.nginx.org
+package v1alpha2
diff --git a/apis/v1alpha1/nginxproxy_types.go b/apis/v1alpha2/nginxproxy_types.go
similarity index 86%
rename from apis/v1alpha1/nginxproxy_types.go
rename to apis/v1alpha2/nginxproxy_types.go
index 6292962ec2..b3a7835887 100644
--- a/apis/v1alpha1/nginxproxy_types.go
+++ b/apis/v1alpha2/nginxproxy_types.go
@@ -1,15 +1,23 @@
-package v1alpha1
+package v1alpha2
-import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+)
// +genclient
// +kubebuilder:object:root=true
// +kubebuilder:storageversion
-// +kubebuilder:resource:categories=nginx-gateway-fabric,scope=Cluster
+// +kubebuilder:resource:categories=nginx-gateway-fabric,scope=Namespaced
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
-// NginxProxy is a configuration object that is attached to a GatewayClass parametersRef. It provides a way
-// to configure global settings for all Gateways defined from the GatewayClass.
+// NginxProxy is a configuration object that can be referenced from a GatewayClass parametersRef
+// or a Gateway infrastructure.parametersRef. It provides a way to configure data plane settings.
+// If referenced from a GatewayClass, the settings apply to all Gateways attached to the GatewayClass.
+// If referenced from a Gateway, the settings apply to that Gateway alone. If both a Gateway and its GatewayClass
+// reference an NginxProxy, the settings are merged. Settings specified on the Gateway NginxProxy override those
+// set on the GatewayClass NginxProxy.
type NginxProxy struct { //nolint:govet // standard field alignment, don't change it
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
@@ -50,14 +58,18 @@ type NginxProxySpec struct {
// +optional
Logging *NginxLogging `json:"logging,omitempty"`
// DisableHTTP2 defines if http2 should be disabled for all servers.
- // Default is false, meaning http2 will be enabled for all servers.
+ // If not specified, or set to false, http2 will be enabled for all servers.
//
// +optional
- DisableHTTP2 bool `json:"disableHTTP2,omitempty"`
+ DisableHTTP2 *bool `json:"disableHTTP2,omitempty"`
}
// Telemetry specifies the OpenTelemetry configuration.
type Telemetry struct {
+ // DisabledFeatures specifies OpenTelemetry features to be disabled.
+ //
+ // +optional
+ DisabledFeatures []DisableTelemetryFeature `json:"disabledFeatures,omitempty"`
// Exporter specifies OpenTelemetry export parameters.
//
// +optional
@@ -78,7 +90,7 @@ type Telemetry struct {
// +listType=map
// +listMapKey=key
// +kubebuilder:validation:MaxItems=64
- SpanAttributes []SpanAttribute `json:"spanAttributes,omitempty"`
+ SpanAttributes []v1alpha1.SpanAttribute `json:"spanAttributes,omitempty"`
}
// TelemetryExporter specifies OpenTelemetry export parameters.
@@ -87,7 +99,7 @@ type TelemetryExporter struct {
// Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter
//
// +optional
- Interval *Duration `json:"interval,omitempty"`
+ Interval *v1alpha1.Duration `json:"interval,omitempty"`
// BatchSize is the maximum number of spans to be sent in one batch per worker.
// Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter
@@ -107,8 +119,9 @@ type TelemetryExporter struct {
// Format: alphanumeric hostname with optional http scheme and optional port.
//
//nolint:lll
+ // +optional
// +kubebuilder:validation:Pattern=`^(?:http?:\/\/)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*(?::\d{1,5})?$`
- Endpoint string `json:"endpoint"`
+ Endpoint *string `json:"endpoint,omitempty"`
}
// RewriteClientIP specifies the configuration for rewriting the client's IP address.
@@ -139,15 +152,12 @@ type RewriteClientIP struct {
// If a request comes from a trusted address, NGINX will rewrite the client IP information,
// and forward it to the backend in the X-Forwarded-For* and X-Real-IP headers.
// If the request does not come from a trusted address, NGINX will not rewrite the client IP information.
- // TrustedAddresses only supports CIDR blocks: 192.33.21.1/24, fe80::1/64.
// To trust all addresses (not recommended for production), set to 0.0.0.0/0.
// If no addresses are provided, NGINX will not rewrite the client IP information.
// Sets NGINX directive set_real_ip_from: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from
// This field is required if mode is set.
//
// +optional
- // +listType=map
- // +listMapKey=type
// +kubebuilder:validation:MaxItems=16
TrustedAddresses []Address `json:"trustedAddresses,omitempty"`
}
@@ -249,3 +259,13 @@ const (
// NginxLogLevelEmerg is the emerg level for NGINX error logs.
NginxLogLevelEmerg NginxErrorLogLevel = "emerg"
)
+
+// DisableTelemetryFeature is a telemetry feature that can be disabled.
+//
+// +kubebuilder:validation:Enum=DisableTracing
+type DisableTelemetryFeature string
+
+const (
+ // DisableTracing disables the OpenTelemetry tracing feature.
+ DisableTracing DisableTelemetryFeature = "DisableTracing"
+)
diff --git a/apis/v1alpha2/register.go b/apis/v1alpha2/register.go
new file mode 100644
index 0000000000..f4dd5ace32
--- /dev/null
+++ b/apis/v1alpha2/register.go
@@ -0,0 +1,41 @@
+package v1alpha2
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// GroupName specifies the group name used to register the objects.
+const GroupName = "gateway.nginx.org"
+
+// SchemeGroupVersion is group version used to register these objects.
+var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
+
+// Resource takes an unqualified resource and returns a Group qualified GroupResource.
+func Resource(resource string) schema.GroupResource {
+ return SchemeGroupVersion.WithResource(resource).GroupResource()
+}
+
+var (
+ // SchemeBuilder collects functions that add things to a scheme. It's to allow
+ // code to compile without explicitly referencing generated types. You should
+ // declare one in each package that will have generated deep copy or conversion
+ // functions.
+ SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+
+ // AddToScheme applies all the stored functions to the scheme. A non-nil error
+ // indicates that one function failed and the attempt was abandoned.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
+
+// Adds the list of known types to Scheme.
+func addKnownTypes(scheme *runtime.Scheme) error {
+ scheme.AddKnownTypes(SchemeGroupVersion,
+ &NginxProxy{},
+ &NginxProxyList{},
+ )
+ // AddToGroupVersion allows the serialization of client types like ListOptions.
+ metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
+ return nil
+}
diff --git a/apis/v1alpha2/zz_generated.deepcopy.go b/apis/v1alpha2/zz_generated.deepcopy.go
new file mode 100644
index 0000000000..0518e7f0c2
--- /dev/null
+++ b/apis/v1alpha2/zz_generated.deepcopy.go
@@ -0,0 +1,243 @@
+//go:build !ignore_autogenerated
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha2
+
+import (
+ "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Address) DeepCopyInto(out *Address) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Address.
+func (in *Address) DeepCopy() *Address {
+ if in == nil {
+ return nil
+ }
+ out := new(Address)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *NginxLogging) DeepCopyInto(out *NginxLogging) {
+ *out = *in
+ if in.ErrorLevel != nil {
+ in, out := &in.ErrorLevel, &out.ErrorLevel
+ *out = new(NginxErrorLogLevel)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NginxLogging.
+func (in *NginxLogging) DeepCopy() *NginxLogging {
+ if in == nil {
+ return nil
+ }
+ out := new(NginxLogging)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *NginxProxy) DeepCopyInto(out *NginxProxy) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NginxProxy.
+func (in *NginxProxy) DeepCopy() *NginxProxy {
+ if in == nil {
+ return nil
+ }
+ out := new(NginxProxy)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *NginxProxy) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *NginxProxyList) DeepCopyInto(out *NginxProxyList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]NginxProxy, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NginxProxyList.
+func (in *NginxProxyList) DeepCopy() *NginxProxyList {
+ if in == nil {
+ return nil
+ }
+ out := new(NginxProxyList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *NginxProxyList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *NginxProxySpec) DeepCopyInto(out *NginxProxySpec) {
+ *out = *in
+ if in.IPFamily != nil {
+ in, out := &in.IPFamily, &out.IPFamily
+ *out = new(IPFamilyType)
+ **out = **in
+ }
+ if in.Telemetry != nil {
+ in, out := &in.Telemetry, &out.Telemetry
+ *out = new(Telemetry)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.RewriteClientIP != nil {
+ in, out := &in.RewriteClientIP, &out.RewriteClientIP
+ *out = new(RewriteClientIP)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Logging != nil {
+ in, out := &in.Logging, &out.Logging
+ *out = new(NginxLogging)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.DisableHTTP2 != nil {
+ in, out := &in.DisableHTTP2, &out.DisableHTTP2
+ *out = new(bool)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NginxProxySpec.
+func (in *NginxProxySpec) DeepCopy() *NginxProxySpec {
+ if in == nil {
+ return nil
+ }
+ out := new(NginxProxySpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *RewriteClientIP) DeepCopyInto(out *RewriteClientIP) {
+ *out = *in
+ if in.Mode != nil {
+ in, out := &in.Mode, &out.Mode
+ *out = new(RewriteClientIPModeType)
+ **out = **in
+ }
+ if in.SetIPRecursively != nil {
+ in, out := &in.SetIPRecursively, &out.SetIPRecursively
+ *out = new(bool)
+ **out = **in
+ }
+ if in.TrustedAddresses != nil {
+ in, out := &in.TrustedAddresses, &out.TrustedAddresses
+ *out = make([]Address, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RewriteClientIP.
+func (in *RewriteClientIP) DeepCopy() *RewriteClientIP {
+ if in == nil {
+ return nil
+ }
+ out := new(RewriteClientIP)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Telemetry) DeepCopyInto(out *Telemetry) {
+ *out = *in
+ if in.DisabledFeatures != nil {
+ in, out := &in.DisabledFeatures, &out.DisabledFeatures
+ *out = make([]DisableTelemetryFeature, len(*in))
+ copy(*out, *in)
+ }
+ if in.Exporter != nil {
+ in, out := &in.Exporter, &out.Exporter
+ *out = new(TelemetryExporter)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.ServiceName != nil {
+ in, out := &in.ServiceName, &out.ServiceName
+ *out = new(string)
+ **out = **in
+ }
+ if in.SpanAttributes != nil {
+ in, out := &in.SpanAttributes, &out.SpanAttributes
+ *out = make([]v1alpha1.SpanAttribute, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Telemetry.
+func (in *Telemetry) DeepCopy() *Telemetry {
+ if in == nil {
+ return nil
+ }
+ out := new(Telemetry)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TelemetryExporter) DeepCopyInto(out *TelemetryExporter) {
+ *out = *in
+ if in.Interval != nil {
+ in, out := &in.Interval, &out.Interval
+ *out = new(v1alpha1.Duration)
+ **out = **in
+ }
+ if in.BatchSize != nil {
+ in, out := &in.BatchSize, &out.BatchSize
+ *out = new(int32)
+ **out = **in
+ }
+ if in.BatchCount != nil {
+ in, out := &in.BatchCount, &out.BatchCount
+ *out = new(int32)
+ **out = **in
+ }
+ if in.Endpoint != nil {
+ in, out := &in.Endpoint, &out.Endpoint
+ *out = new(string)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TelemetryExporter.
+func (in *TelemetryExporter) DeepCopy() *TelemetryExporter {
+ if in == nil {
+ return nil
+ }
+ out := new(TelemetryExporter)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/charts/nginx-gateway-fabric/templates/gatewayclass.yaml b/charts/nginx-gateway-fabric/templates/gatewayclass.yaml
index ee08e1a726..aecd54e8ad 100644
--- a/charts/nginx-gateway-fabric/templates/gatewayclass.yaml
+++ b/charts/nginx-gateway-fabric/templates/gatewayclass.yaml
@@ -17,4 +17,5 @@ spec:
group: gateway.nginx.org
kind: NginxProxy
name: {{ include "nginx-gateway.proxy-config-name" . }}
+ namespace: {{ .Release.Namespace }}
{{- end }}
diff --git a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml
index 4214158b75..bc4105ee37 100644
--- a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml
+++ b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml
@@ -1,8 +1,9 @@
{{- if .Values.nginx.config }}
-apiVersion: gateway.nginx.org/v1alpha1
+apiVersion: gateway.nginx.org/v1alpha2
kind: NginxProxy
metadata:
name: {{ include "nginx-gateway.proxy-config-name" . }}
+ namespace: {{ .Release.Namespace }}
labels:
{{- include "nginx-gateway.labels" . | nindent 4 }}
spec:
diff --git a/charts/nginx-gateway-fabric/values.schema.json b/charts/nginx-gateway-fabric/values.schema.json
index 651fea311c..2cbf5f3082 100644
--- a/charts/nginx-gateway-fabric/values.schema.json
+++ b/charts/nginx-gateway-fabric/values.schema.json
@@ -137,6 +137,17 @@
"telemetry": {
"description": "Telemetry specifies the OpenTelemetry configuration.",
"properties": {
+ "disabledFeatures": {
+ "items": {
+ "enum": [
+ "DisableTracing"
+ ],
+ "required": [],
+ "type": "string"
+ },
+ "required": [],
+ "type": "array"
+ },
"exporter": {
"properties": {
"batchCount": {
diff --git a/charts/nginx-gateway-fabric/values.yaml b/charts/nginx-gateway-fabric/values.yaml
index 4168c3d66e..e59b764c4e 100644
--- a/charts/nginx-gateway-fabric/values.yaml
+++ b/charts/nginx-gateway-fabric/values.yaml
@@ -233,6 +233,12 @@ nginx:
# pattern: ^([^"$\\]|\\[^$])*$
# minLength: 1
# maxLength: 255
+ # disabledFeatures:
+ # type: array
+ # items:
+ # type: string
+ # enum:
+ # - DisableTracing
# logging:
# type: object
# description: Logging defines logging related settings for NGINX.
diff --git a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml
index 21b61ce37f..9a641ea996 100644
--- a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml
+++ b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml
@@ -14,18 +14,22 @@ spec:
listKind: NginxProxyList
plural: nginxproxies
singular: nginxproxy
- scope: Cluster
+ scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
- name: v1alpha1
+ name: v1alpha2
schema:
openAPIV3Schema:
description: |-
- NginxProxy is a configuration object that is attached to a GatewayClass parametersRef. It provides a way
- to configure global settings for all Gateways defined from the GatewayClass.
+ NginxProxy is a configuration object that can be referenced from a GatewayClass parametersRef
+ or a Gateway infrastructure.parametersRef. It provides a way to configure data plane settings.
+ If referenced from a GatewayClass, the settings apply to all Gateways attached to the GatewayClass.
+ If referenced from a Gateway, the settings apply to that Gateway alone. If both a Gateway and its GatewayClass
+ reference an NginxProxy, the settings are merged. Settings specified on the Gateway NginxProxy override those
+ set on the GatewayClass NginxProxy.
properties:
apiVersion:
description: |-
@@ -50,7 +54,7 @@ spec:
disableHTTP2:
description: |-
DisableHTTP2 defines if http2 should be disabled for all servers.
- Default is false, meaning http2 will be enabled for all servers.
+ If not specified, or set to false, http2 will be enabled for all servers.
type: boolean
ipFamily:
default: dual
@@ -116,7 +120,6 @@ spec:
If a request comes from a trusted address, NGINX will rewrite the client IP information,
and forward it to the backend in the X-Forwarded-For* and X-Real-IP headers.
If the request does not come from a trusted address, NGINX will not rewrite the client IP information.
- TrustedAddresses only supports CIDR blocks: 192.33.21.1/24, fe80::1/64.
To trust all addresses (not recommended for production), set to 0.0.0.0/0.
If no addresses are provided, NGINX will not rewrite the client IP information.
Sets NGINX directive set_real_ip_from: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from
@@ -141,9 +144,6 @@ spec:
type: object
maxItems: 16
type: array
- x-kubernetes-list-map-keys:
- - type
- x-kubernetes-list-type: map
type: object
x-kubernetes-validations:
- message: if mode is set, trustedAddresses is a required field
@@ -152,6 +152,16 @@ spec:
telemetry:
description: Telemetry specifies the OpenTelemetry configuration.
properties:
+ disabledFeatures:
+ description: DisabledFeatures specifies OpenTelemetry features
+ to be disabled.
+ items:
+ description: DisableTelemetryFeature is a telemetry feature
+ that can be disabled.
+ enum:
+ - DisableTracing
+ type: string
+ type: array
exporter:
description: Exporter specifies OpenTelemetry export parameters.
properties:
@@ -181,8 +191,6 @@ spec:
Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter
pattern: ^[0-9]{1,4}(ms|s|m|h)?$
type: string
- required:
- - endpoint
type: object
serviceName:
description: |-
diff --git a/deploy/crds.yaml b/deploy/crds.yaml
index 5a9d708c60..b6d058d53a 100644
--- a/deploy/crds.yaml
+++ b/deploy/crds.yaml
@@ -599,18 +599,22 @@ spec:
listKind: NginxProxyList
plural: nginxproxies
singular: nginxproxy
- scope: Cluster
+ scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
- name: v1alpha1
+ name: v1alpha2
schema:
openAPIV3Schema:
description: |-
- NginxProxy is a configuration object that is attached to a GatewayClass parametersRef. It provides a way
- to configure global settings for all Gateways defined from the GatewayClass.
+ NginxProxy is a configuration object that can be referenced from a GatewayClass parametersRef
+ or a Gateway infrastructure.parametersRef. It provides a way to configure data plane settings.
+ If referenced from a GatewayClass, the settings apply to all Gateways attached to the GatewayClass.
+ If referenced from a Gateway, the settings apply to that Gateway alone. If both a Gateway and its GatewayClass
+ reference an NginxProxy, the settings are merged. Settings specified on the Gateway NginxProxy override those
+ set on the GatewayClass NginxProxy.
properties:
apiVersion:
description: |-
@@ -635,7 +639,7 @@ spec:
disableHTTP2:
description: |-
DisableHTTP2 defines if http2 should be disabled for all servers.
- Default is false, meaning http2 will be enabled for all servers.
+ If not specified, or set to false, http2 will be enabled for all servers.
type: boolean
ipFamily:
default: dual
@@ -701,7 +705,6 @@ spec:
If a request comes from a trusted address, NGINX will rewrite the client IP information,
and forward it to the backend in the X-Forwarded-For* and X-Real-IP headers.
If the request does not come from a trusted address, NGINX will not rewrite the client IP information.
- TrustedAddresses only supports CIDR blocks: 192.33.21.1/24, fe80::1/64.
To trust all addresses (not recommended for production), set to 0.0.0.0/0.
If no addresses are provided, NGINX will not rewrite the client IP information.
Sets NGINX directive set_real_ip_from: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from
@@ -726,9 +729,6 @@ spec:
type: object
maxItems: 16
type: array
- x-kubernetes-list-map-keys:
- - type
- x-kubernetes-list-type: map
type: object
x-kubernetes-validations:
- message: if mode is set, trustedAddresses is a required field
@@ -737,6 +737,16 @@ spec:
telemetry:
description: Telemetry specifies the OpenTelemetry configuration.
properties:
+ disabledFeatures:
+ description: DisabledFeatures specifies OpenTelemetry features
+ to be disabled.
+ items:
+ description: DisableTelemetryFeature is a telemetry feature
+ that can be disabled.
+ enum:
+ - DisableTracing
+ type: string
+ type: array
exporter:
description: Exporter specifies OpenTelemetry export parameters.
properties:
@@ -766,8 +776,6 @@ spec:
Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter
pattern: ^[0-9]{1,4}(ms|s|m|h)?$
type: string
- required:
- - endpoint
type: object
serviceName:
description: |-
diff --git a/internal/mode/static/manager.go b/internal/mode/static/manager.go
index b6da949c52..c5df4d1495 100644
--- a/internal/mode/static/manager.go
+++ b/internal/mode/static/manager.go
@@ -34,7 +34,8 @@ import (
gatewayv1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3"
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/controller"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/controller/filter"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/controller/index"
@@ -84,7 +85,8 @@ func init() {
utilruntime.Must(gatewayv1alpha2.Install(scheme))
utilruntime.Must(apiv1.AddToScheme(scheme))
utilruntime.Must(discoveryV1.AddToScheme(scheme))
- utilruntime.Must(ngfAPI.AddToScheme(scheme))
+ utilruntime.Must(ngfAPIv1alpha1.AddToScheme(scheme))
+ utilruntime.Must(ngfAPIv1alpha2.AddToScheme(scheme))
utilruntime.Must(apiext.AddToScheme(scheme))
utilruntime.Must(appsv1.AddToScheme(scheme))
}
@@ -276,15 +278,15 @@ func createPolicyManager(
) *policies.CompositeValidator {
cfgs := []policies.ManagerConfig{
{
- GVK: mustExtractGVK(&ngfAPI.ClientSettingsPolicy{}),
+ GVK: mustExtractGVK(&ngfAPIv1alpha1.ClientSettingsPolicy{}),
Validator: clientsettings.NewValidator(validator),
},
{
- GVK: mustExtractGVK(&ngfAPI.ObservabilityPolicy{}),
+ GVK: mustExtractGVK(&ngfAPIv1alpha1.ObservabilityPolicy{}),
Validator: observability.NewValidator(validator),
},
{
- GVK: mustExtractGVK(&ngfAPI.UpstreamSettingsPolicy{}),
+ GVK: mustExtractGVK(&ngfAPIv1alpha1.UpstreamSettingsPolicy{}),
Validator: upstreamsettings.NewValidator(validator),
},
}
@@ -445,7 +447,7 @@ func registerControllers(
},
},
{
- objectType: &ngfAPI.NginxProxy{},
+ objectType: &ngfAPIv1alpha2.NginxProxy{},
options: []controller.Option{
controller.WithK8sPredicate(k8spredicate.GenerationChangedPredicate{}),
},
@@ -457,19 +459,19 @@ func registerControllers(
},
},
{
- objectType: &ngfAPI.ClientSettingsPolicy{},
+ objectType: &ngfAPIv1alpha1.ClientSettingsPolicy{},
options: []controller.Option{
controller.WithK8sPredicate(k8spredicate.GenerationChangedPredicate{}),
},
},
{
- objectType: &ngfAPI.ObservabilityPolicy{},
+ objectType: &ngfAPIv1alpha1.ObservabilityPolicy{},
options: []controller.Option{
controller.WithK8sPredicate(k8spredicate.GenerationChangedPredicate{}),
},
},
{
- objectType: &ngfAPI.UpstreamSettingsPolicy{},
+ objectType: &ngfAPIv1alpha1.UpstreamSettingsPolicy{},
options: []controller.Option{
controller.WithK8sPredicate(k8spredicate.GenerationChangedPredicate{}),
},
@@ -502,7 +504,7 @@ func registerControllers(
if cfg.ConfigName != "" {
controllerRegCfgs = append(controllerRegCfgs,
ctlrCfg{
- objectType: &ngfAPI.NginxGateway{},
+ objectType: &ngfAPIv1alpha1.NginxGateway{},
options: []controller.Option{
controller.WithNamespacedNameFilter(filter.CreateSingleResourceFilter(controlConfigNSName)),
},
@@ -521,7 +523,7 @@ func registerControllers(
if cfg.SnippetsFilters {
controllerRegCfgs = append(controllerRegCfgs,
ctlrCfg{
- objectType: &ngfAPI.SnippetsFilter{},
+ objectType: &ngfAPIv1alpha1.SnippetsFilter{},
options: []controller.Option{
controller.WithK8sPredicate(k8spredicate.GenerationChangedPredicate{}),
},
@@ -706,11 +708,11 @@ func prepareFirstEventBatchPreparerArgs(cfg config.Config) ([]client.Object, []c
&discoveryV1.EndpointSliceList{},
&gatewayv1.HTTPRouteList{},
&gatewayv1beta1.ReferenceGrantList{},
- &ngfAPI.NginxProxyList{},
+ &ngfAPIv1alpha2.NginxProxyList{},
&gatewayv1.GRPCRouteList{},
- &ngfAPI.ClientSettingsPolicyList{},
- &ngfAPI.ObservabilityPolicyList{},
- &ngfAPI.UpstreamSettingsPolicyList{},
+ &ngfAPIv1alpha1.ClientSettingsPolicyList{},
+ &ngfAPIv1alpha1.ObservabilityPolicyList{},
+ &ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
partialObjectMetadataList,
}
@@ -726,7 +728,7 @@ func prepareFirstEventBatchPreparerArgs(cfg config.Config) ([]client.Object, []c
if cfg.SnippetsFilters {
objectLists = append(
objectLists,
- &ngfAPI.SnippetsFilterList{},
+ &ngfAPIv1alpha1.SnippetsFilterList{},
)
}
@@ -754,7 +756,7 @@ func setInitialConfig(
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- var conf ngfAPI.NginxGateway
+ var conf ngfAPIv1alpha1.NginxGateway
// Polling to wait for CRD to exist if the Deployment is created first.
if err := wait.PollUntilContextCancel(
ctx,
diff --git a/internal/mode/static/manager_test.go b/internal/mode/static/manager_test.go
index 0f2d802d32..d2206a633c 100644
--- a/internal/mode/static/manager_test.go
+++ b/internal/mode/static/manager_test.go
@@ -19,7 +19,8 @@ import (
gatewayv1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3"
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/config"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/graph"
)
@@ -62,12 +63,12 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
&gatewayv1.HTTPRouteList{},
&gatewayv1.GatewayList{},
&gatewayv1beta1.ReferenceGrantList{},
- &ngfAPI.NginxProxyList{},
+ &ngfAPIv1alpha2.NginxProxyList{},
&gatewayv1.GRPCRouteList{},
partialObjectMetadataList,
- &ngfAPI.ClientSettingsPolicyList{},
- &ngfAPI.ObservabilityPolicyList{},
- &ngfAPI.UpstreamSettingsPolicyList{},
+ &ngfAPIv1alpha1.ClientSettingsPolicyList{},
+ &ngfAPIv1alpha1.ObservabilityPolicyList{},
+ &ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
},
},
{
@@ -92,12 +93,12 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
&discoveryV1.EndpointSliceList{},
&gatewayv1.HTTPRouteList{},
&gatewayv1beta1.ReferenceGrantList{},
- &ngfAPI.NginxProxyList{},
+ &ngfAPIv1alpha2.NginxProxyList{},
&gatewayv1.GRPCRouteList{},
partialObjectMetadataList,
- &ngfAPI.ClientSettingsPolicyList{},
- &ngfAPI.ObservabilityPolicyList{},
- &ngfAPI.UpstreamSettingsPolicyList{},
+ &ngfAPIv1alpha1.ClientSettingsPolicyList{},
+ &ngfAPIv1alpha1.ObservabilityPolicyList{},
+ &ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
},
},
{
@@ -123,14 +124,14 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
&discoveryV1.EndpointSliceList{},
&gatewayv1.HTTPRouteList{},
&gatewayv1beta1.ReferenceGrantList{},
- &ngfAPI.NginxProxyList{},
+ &ngfAPIv1alpha2.NginxProxyList{},
partialObjectMetadataList,
&gatewayv1alpha3.BackendTLSPolicyList{},
&gatewayv1alpha2.TLSRouteList{},
&gatewayv1.GRPCRouteList{},
- &ngfAPI.ClientSettingsPolicyList{},
- &ngfAPI.ObservabilityPolicyList{},
- &ngfAPI.UpstreamSettingsPolicyList{},
+ &ngfAPIv1alpha1.ClientSettingsPolicyList{},
+ &ngfAPIv1alpha1.ObservabilityPolicyList{},
+ &ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
},
},
{
@@ -155,13 +156,13 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
&discoveryV1.EndpointSliceList{},
&gatewayv1.HTTPRouteList{},
&gatewayv1beta1.ReferenceGrantList{},
- &ngfAPI.NginxProxyList{},
+ &ngfAPIv1alpha2.NginxProxyList{},
partialObjectMetadataList,
&gatewayv1.GRPCRouteList{},
- &ngfAPI.ClientSettingsPolicyList{},
- &ngfAPI.ObservabilityPolicyList{},
- &ngfAPI.SnippetsFilterList{},
- &ngfAPI.UpstreamSettingsPolicyList{},
+ &ngfAPIv1alpha1.ClientSettingsPolicyList{},
+ &ngfAPIv1alpha1.ObservabilityPolicyList{},
+ &ngfAPIv1alpha1.SnippetsFilterList{},
+ &ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
},
},
{
@@ -187,15 +188,15 @@ func TestPrepareFirstEventBatchPreparerArgs(t *testing.T) {
&discoveryV1.EndpointSliceList{},
&gatewayv1.HTTPRouteList{},
&gatewayv1beta1.ReferenceGrantList{},
- &ngfAPI.NginxProxyList{},
+ &ngfAPIv1alpha2.NginxProxyList{},
partialObjectMetadataList,
&gatewayv1alpha3.BackendTLSPolicyList{},
&gatewayv1alpha2.TLSRouteList{},
&gatewayv1.GRPCRouteList{},
- &ngfAPI.ClientSettingsPolicyList{},
- &ngfAPI.ObservabilityPolicyList{},
- &ngfAPI.SnippetsFilterList{},
- &ngfAPI.UpstreamSettingsPolicyList{},
+ &ngfAPIv1alpha1.ClientSettingsPolicyList{},
+ &ngfAPIv1alpha1.ObservabilityPolicyList{},
+ &ngfAPIv1alpha1.SnippetsFilterList{},
+ &ngfAPIv1alpha1.UpstreamSettingsPolicyList{},
},
},
}
diff --git a/internal/mode/static/state/change_processor.go b/internal/mode/static/state/change_processor.go
index 82edbcc7b1..8a889ae81d 100644
--- a/internal/mode/static/state/change_processor.go
+++ b/internal/mode/static/state/change_processor.go
@@ -16,7 +16,8 @@ import (
"sigs.k8s.io/gateway-api/apis/v1alpha3"
"sigs.k8s.io/gateway-api/apis/v1beta1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/gatewayclass"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds"
ngftypes "github.com/nginxinc/nginx-gateway-fabric/internal/framework/types"
@@ -108,11 +109,11 @@ func NewChangeProcessorImpl(cfg ChangeProcessorConfig) *ChangeProcessorImpl {
CRDMetadata: make(map[types.NamespacedName]*metav1.PartialObjectMetadata),
BackendTLSPolicies: make(map[types.NamespacedName]*v1alpha3.BackendTLSPolicy),
ConfigMaps: make(map[types.NamespacedName]*apiv1.ConfigMap),
- NginxProxies: make(map[types.NamespacedName]*ngfAPI.NginxProxy),
+ NginxProxies: make(map[types.NamespacedName]*ngfAPIv1alpha2.NginxProxy),
GRPCRoutes: make(map[types.NamespacedName]*v1.GRPCRoute),
TLSRoutes: make(map[types.NamespacedName]*v1alpha2.TLSRoute),
NGFPolicies: make(map[graph.PolicyKey]policies.Policy),
- SnippetsFilters: make(map[types.NamespacedName]*ngfAPI.SnippetsFilter),
+ SnippetsFilters: make(map[types.NamespacedName]*ngfAPIv1alpha1.SnippetsFilter),
}
processor := &ChangeProcessorImpl{
@@ -202,22 +203,22 @@ func NewChangeProcessorImpl(cfg ChangeProcessorConfig) *ChangeProcessorImpl {
predicate: annotationChangedPredicate{annotation: gatewayclass.BundleVersionAnnotation},
},
{
- gvk: cfg.MustExtractGVK(&ngfAPI.NginxProxy{}),
+ gvk: cfg.MustExtractGVK(&ngfAPIv1alpha2.NginxProxy{}),
store: newObjectStoreMapAdapter(clusterStore.NginxProxies),
predicate: funcPredicate{stateChanged: isReferenced},
},
{
- gvk: cfg.MustExtractGVK(&ngfAPI.ClientSettingsPolicy{}),
+ gvk: cfg.MustExtractGVK(&ngfAPIv1alpha1.ClientSettingsPolicy{}),
store: commonPolicyObjectStore,
predicate: funcPredicate{stateChanged: isNGFPolicyRelevant},
},
{
- gvk: cfg.MustExtractGVK(&ngfAPI.ObservabilityPolicy{}),
+ gvk: cfg.MustExtractGVK(&ngfAPIv1alpha1.ObservabilityPolicy{}),
store: commonPolicyObjectStore,
predicate: funcPredicate{stateChanged: isNGFPolicyRelevant},
},
{
- gvk: cfg.MustExtractGVK(&ngfAPI.UpstreamSettingsPolicy{}),
+ gvk: cfg.MustExtractGVK(&ngfAPIv1alpha1.UpstreamSettingsPolicy{}),
store: commonPolicyObjectStore,
predicate: funcPredicate{stateChanged: isNGFPolicyRelevant},
},
@@ -227,7 +228,7 @@ func NewChangeProcessorImpl(cfg ChangeProcessorConfig) *ChangeProcessorImpl {
predicate: nil,
},
{
- gvk: cfg.MustExtractGVK(&ngfAPI.SnippetsFilter{}),
+ gvk: cfg.MustExtractGVK(&ngfAPIv1alpha1.SnippetsFilter{}),
store: newObjectStoreMapAdapter(clusterStore.SnippetsFilters),
predicate: nil, // we always want to write status to SnippetsFilters so we don't filter them out
},
diff --git a/internal/mode/static/state/change_processor_test.go b/internal/mode/static/state/change_processor_test.go
index 03d86a377b..85c59099c1 100644
--- a/internal/mode/static/state/change_processor_test.go
+++ b/internal/mode/static/state/change_processor_test.go
@@ -19,7 +19,8 @@ import (
"sigs.k8s.io/gateway-api/apis/v1alpha3"
"sigs.k8s.io/gateway-api/apis/v1beta1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/controller/index"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/gatewayclass"
@@ -326,7 +327,8 @@ func createScheme() *runtime.Scheme {
utilruntime.Must(apiv1.AddToScheme(scheme))
utilruntime.Must(discoveryV1.AddToScheme(scheme))
utilruntime.Must(apiext.AddToScheme(scheme))
- utilruntime.Must(ngfAPI.AddToScheme(scheme))
+ utilruntime.Must(ngfAPIv1alpha1.AddToScheme(scheme))
+ utilruntime.Must(ngfAPIv1alpha2.AddToScheme(scheme))
return scheme
}
@@ -2289,56 +2291,135 @@ var _ = Describe("ChangeProcessor", func() {
})
Describe("NginxProxy resource changes", Ordered, func() {
- paramGC := gc.DeepCopy()
- paramGC.Spec.ParametersRef = &v1beta1.ParametersReference{
- Group: ngfAPI.GroupName,
- Kind: kinds.NginxProxy,
- Name: "np",
- }
+ Context("referenced by a GatewayClass", func() {
+ paramGC := gc.DeepCopy()
+ paramGC.Spec.ParametersRef = &v1beta1.ParametersReference{
+ Group: ngfAPIv1alpha1.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: "np",
+ Namespace: helpers.GetPointer[v1.Namespace]("test"),
+ }
- np := &ngfAPI.NginxProxy{
- ObjectMeta: metav1.ObjectMeta{
- Name: "np",
- },
- }
+ np := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "np",
+ Namespace: "test",
+ },
+ }
- npUpdated := &ngfAPI.NginxProxy{
- ObjectMeta: metav1.ObjectMeta{
- Name: "np",
- },
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- Exporter: &ngfAPI.TelemetryExporter{
- Endpoint: "my-svc:123",
- BatchSize: helpers.GetPointer(int32(512)),
- BatchCount: helpers.GetPointer(int32(4)),
- Interval: helpers.GetPointer(ngfAPI.Duration("5s")),
+ npUpdated := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "np",
+ Namespace: "test",
+ },
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("my-svc:123"),
+ BatchSize: helpers.GetPointer(int32(512)),
+ BatchCount: helpers.GetPointer(int32(4)),
+ Interval: helpers.GetPointer(ngfAPIv1alpha1.Duration("5s")),
+ },
},
},
- },
- }
- It("handles upserts for an NginxProxy", func() {
- processor.CaptureUpsertChange(np)
- processor.CaptureUpsertChange(paramGC)
+ }
+ It("handles upserts for an NginxProxy", func() {
+ processor.CaptureUpsertChange(np)
+ processor.CaptureUpsertChange(paramGC)
- changed, graph := processor.Process()
- Expect(changed).To(Equal(state.ClusterStateChange))
- Expect(graph.NginxProxy.Source).To(Equal(np))
- })
- It("captures changes for an NginxProxy", func() {
- processor.CaptureUpsertChange(npUpdated)
- processor.CaptureUpsertChange(paramGC)
+ changed, graph := processor.Process()
+ Expect(changed).To(Equal(state.ClusterStateChange))
+ Expect(graph.GatewayClass.NginxProxy.Source).To(Equal(np))
+ })
+ It("captures changes for an NginxProxy", func() {
+ processor.CaptureUpsertChange(npUpdated)
+ processor.CaptureUpsertChange(paramGC)
- changed, graph := processor.Process()
- Expect(changed).To(Equal(state.ClusterStateChange))
- Expect(graph.NginxProxy.Source).To(Equal(npUpdated))
+ changed, graph := processor.Process()
+ Expect(changed).To(Equal(state.ClusterStateChange))
+ Expect(graph.GatewayClass.NginxProxy.Source).To(Equal(npUpdated))
+ })
+ It("handles deletes for an NginxProxy", func() {
+ processor.CaptureDeleteChange(np, client.ObjectKeyFromObject(np))
+
+ changed, graph := processor.Process()
+ Expect(changed).To(Equal(state.ClusterStateChange))
+ Expect(graph.GatewayClass.NginxProxy).To(BeNil())
+ })
})
- It("handles deletes for an NginxProxy", func() {
- processor.CaptureDeleteChange(np, client.ObjectKeyFromObject(np))
+ Context("referenced by a Gateway", func() {
+ paramGW := &v1.Gateway{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "test",
+ Name: "param-gw",
+ Generation: 1,
+ },
+ Spec: v1.GatewaySpec{
+ GatewayClassName: gcName,
+ Listeners: []v1.Listener{
+ {
+ Name: httpListenerName,
+ Hostname: nil,
+ Port: 80,
+ Protocol: v1.HTTPProtocolType,
+ },
+ },
+ Infrastructure: &v1.GatewayInfrastructure{
+ ParametersRef: &v1.LocalParametersReference{
+ Group: ngfAPIv1alpha1.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: "np-gw",
+ },
+ },
+ },
+ }
- changed, graph := processor.Process()
- Expect(changed).To(Equal(state.ClusterStateChange))
- Expect(graph.NginxProxy).To(BeNil())
+ np := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "np-gw",
+ Namespace: "test",
+ },
+ }
+
+ npUpdated := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "np-gw",
+ Namespace: "test",
+ },
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("my-svc:123"),
+ BatchSize: helpers.GetPointer(int32(512)),
+ BatchCount: helpers.GetPointer(int32(4)),
+ Interval: helpers.GetPointer(ngfAPIv1alpha1.Duration("5s")),
+ },
+ },
+ },
+ }
+ It("handles upserts for an NginxProxy", func() {
+ processor.CaptureUpsertChange(np)
+ processor.CaptureUpsertChange(paramGW)
+
+ changed, graph := processor.Process()
+ Expect(changed).To(Equal(state.ClusterStateChange))
+ Expect(graph.Gateway.NginxProxy.Source).To(Equal(np))
+ })
+ It("captures changes for an NginxProxy", func() {
+ processor.CaptureUpsertChange(npUpdated)
+ processor.CaptureUpsertChange(paramGW)
+
+ changed, graph := processor.Process()
+ Expect(changed).To(Equal(state.ClusterStateChange))
+ Expect(graph.Gateway.NginxProxy.Source).To(Equal(npUpdated))
+ })
+ It("handles deletes for an NginxProxy", func() {
+ processor.CaptureDeleteChange(np, client.ObjectKeyFromObject(np))
+
+ changed, graph := processor.Process()
+ Expect(changed).To(Equal(state.ClusterStateChange))
+ Expect(graph.Gateway.NginxProxy).To(BeNil())
+ })
})
})
@@ -2347,9 +2428,9 @@ var _ = Describe("ChangeProcessor", func() {
gw *v1.Gateway
route *v1.HTTPRoute
svc *apiv1.Service
- csp, cspUpdated *ngfAPI.ClientSettingsPolicy
- obs, obsUpdated *ngfAPI.ObservabilityPolicy
- usp, uspUpdated *ngfAPI.UpstreamSettingsPolicy
+ csp, cspUpdated *ngfAPIv1alpha1.ClientSettingsPolicy
+ obs, obsUpdated *ngfAPIv1alpha1.ObservabilityPolicy
+ usp, uspUpdated *ngfAPIv1alpha1.UpstreamSettingsPolicy
cspKey, obsKey, uspKey graph.PolicyKey
)
@@ -2384,41 +2465,41 @@ var _ = Describe("ChangeProcessor", func() {
},
}
- csp = &ngfAPI.ClientSettingsPolicy{
+ csp = &ngfAPIv1alpha1.ClientSettingsPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "csp",
Namespace: "test",
},
- Spec: ngfAPI.ClientSettingsPolicySpec{
+ Spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
TargetRef: v1alpha2.LocalPolicyTargetReference{
Group: v1.GroupName,
Kind: kinds.Gateway,
Name: "gw",
},
- Body: &ngfAPI.ClientBody{
- MaxSize: helpers.GetPointer[ngfAPI.Size]("10m"),
+ Body: &ngfAPIv1alpha1.ClientBody{
+ MaxSize: helpers.GetPointer[ngfAPIv1alpha1.Size]("10m"),
},
},
}
cspUpdated = csp.DeepCopy()
- cspUpdated.Spec.Body.MaxSize = helpers.GetPointer[ngfAPI.Size]("20m")
+ cspUpdated.Spec.Body.MaxSize = helpers.GetPointer[ngfAPIv1alpha1.Size]("20m")
cspKey = graph.PolicyKey{
NsName: types.NamespacedName{Name: "csp", Namespace: "test"},
GVK: schema.GroupVersionKind{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.ClientSettingsPolicy,
Version: "v1alpha1",
},
}
- obs = &ngfAPI.ObservabilityPolicy{
+ obs = &ngfAPIv1alpha1.ObservabilityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "obs",
Namespace: "test",
},
- Spec: ngfAPI.ObservabilityPolicySpec{
+ Spec: ngfAPIv1alpha1.ObservabilityPolicySpec{
TargetRefs: []v1alpha2.LocalPolicyTargetReference{
{
Group: v1.GroupName,
@@ -2426,31 +2507,31 @@ var _ = Describe("ChangeProcessor", func() {
Name: "hr-1",
},
},
- Tracing: &ngfAPI.Tracing{
- Strategy: ngfAPI.TraceStrategyRatio,
+ Tracing: &ngfAPIv1alpha1.Tracing{
+ Strategy: ngfAPIv1alpha1.TraceStrategyRatio,
},
},
}
obsUpdated = obs.DeepCopy()
- obsUpdated.Spec.Tracing.Strategy = ngfAPI.TraceStrategyParent
+ obsUpdated.Spec.Tracing.Strategy = ngfAPIv1alpha1.TraceStrategyParent
obsKey = graph.PolicyKey{
NsName: types.NamespacedName{Name: "obs", Namespace: "test"},
GVK: schema.GroupVersionKind{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.ObservabilityPolicy,
Version: "v1alpha1",
},
}
- usp = &ngfAPI.UpstreamSettingsPolicy{
+ usp = &ngfAPIv1alpha1.UpstreamSettingsPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "usp",
Namespace: "test",
},
- Spec: ngfAPI.UpstreamSettingsPolicySpec{
- ZoneSize: helpers.GetPointer[ngfAPI.Size]("10m"),
+ Spec: ngfAPIv1alpha1.UpstreamSettingsPolicySpec{
+ ZoneSize: helpers.GetPointer[ngfAPIv1alpha1.Size]("10m"),
TargetRefs: []v1alpha2.LocalPolicyTargetReference{
{
Group: "core",
@@ -2462,12 +2543,12 @@ var _ = Describe("ChangeProcessor", func() {
}
uspUpdated = usp.DeepCopy()
- uspUpdated.Spec.ZoneSize = helpers.GetPointer[ngfAPI.Size]("20m")
+ uspUpdated.Spec.ZoneSize = helpers.GetPointer[ngfAPIv1alpha1.Size]("20m")
uspKey = graph.PolicyKey{
NsName: types.NamespacedName{Name: "usp", Namespace: "test"},
GVK: schema.GroupVersionKind{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.UpstreamSettingsPolicy,
Version: "v1alpha1",
},
@@ -2531,9 +2612,9 @@ var _ = Describe("ChangeProcessor", func() {
})
When("the policy is deleted", func() {
It("removes the policy from the graph", func() {
- processor.CaptureDeleteChange(&ngfAPI.ClientSettingsPolicy{}, client.ObjectKeyFromObject(csp))
- processor.CaptureDeleteChange(&ngfAPI.ObservabilityPolicy{}, client.ObjectKeyFromObject(obs))
- processor.CaptureDeleteChange(&ngfAPI.UpstreamSettingsPolicy{}, client.ObjectKeyFromObject(usp))
+ processor.CaptureDeleteChange(&ngfAPIv1alpha1.ClientSettingsPolicy{}, client.ObjectKeyFromObject(csp))
+ processor.CaptureDeleteChange(&ngfAPIv1alpha1.ObservabilityPolicy{}, client.ObjectKeyFromObject(obs))
+ processor.CaptureDeleteChange(&ngfAPIv1alpha1.UpstreamSettingsPolicy{}, client.ObjectKeyFromObject(usp))
changed, graph := processor.Process()
Expect(changed).To(Equal(state.ClusterStateChange))
@@ -2548,34 +2629,34 @@ var _ = Describe("ChangeProcessor", func() {
Namespace: "test",
}
- sf := &ngfAPI.SnippetsFilter{
+ sf := &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: sfNsName.Name,
Namespace: sfNsName.Namespace,
},
- Spec: ngfAPI.SnippetsFilterSpec{
- Snippets: []ngfAPI.Snippet{
+ Spec: ngfAPIv1alpha1.SnippetsFilterSpec{
+ Snippets: []ngfAPIv1alpha1.Snippet{
{
- Context: ngfAPI.NginxContextMain,
+ Context: ngfAPIv1alpha1.NginxContextMain,
Value: "main snippet",
},
},
},
}
- sfUpdated := &ngfAPI.SnippetsFilter{
+ sfUpdated := &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: sfNsName.Name,
Namespace: sfNsName.Namespace,
},
- Spec: ngfAPI.SnippetsFilterSpec{
- Snippets: []ngfAPI.Snippet{
+ Spec: ngfAPIv1alpha1.SnippetsFilterSpec{
+ Snippets: []ngfAPIv1alpha1.Snippet{
{
- Context: ngfAPI.NginxContextMain,
+ Context: ngfAPIv1alpha1.NginxContextMain,
Value: "main snippet",
},
{
- Context: ngfAPI.NginxContextHTTP,
+ Context: ngfAPIv1alpha1.NginxContextHTTP,
Value: "http snippet",
},
},
@@ -2631,7 +2712,7 @@ var _ = Describe("ChangeProcessor", func() {
secret, secretUpdated, unrelatedSecret, barSecret, barSecretUpdated *apiv1.Secret
cm, cmUpdated, unrelatedCM *apiv1.ConfigMap
btls, btlsUpdated *v1alpha3.BackendTLSPolicy
- np, npUpdated *ngfAPI.NginxProxy
+ np, npUpdated *ngfAPIv1alpha2.NginxProxy
)
BeforeEach(OncePerOrdered, func() {
@@ -2930,12 +3011,12 @@ var _ = Describe("ChangeProcessor", func() {
btlsUpdated = btls.DeepCopy()
npNsName = types.NamespacedName{Name: "np-1"}
- np = &ngfAPI.NginxProxy{
+ np = &ngfAPIv1alpha2.NginxProxy{
ObjectMeta: metav1.ObjectMeta{
Name: npNsName.Name,
},
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
ServiceName: helpers.GetPointer("my-svc"),
},
},
@@ -3010,7 +3091,7 @@ var _ = Describe("ChangeProcessor", func() {
processor.CaptureDeleteChange(&v1beta1.ReferenceGrant{}, rgNsName)
processor.CaptureDeleteChange(&v1alpha3.BackendTLSPolicy{}, btlsNsName)
processor.CaptureDeleteChange(&apiv1.ConfigMap{}, cmNsName)
- processor.CaptureDeleteChange(&ngfAPI.NginxProxy{}, npNsName)
+ processor.CaptureDeleteChange(&ngfAPIv1alpha2.NginxProxy{}, npNsName)
// these are non-changing changes
processor.CaptureUpsertChange(gw2)
diff --git a/internal/mode/static/state/conditions/conditions.go b/internal/mode/static/state/conditions/conditions.go
index c97f9efa2d..f49a755d9a 100644
--- a/internal/mode/static/state/conditions/conditions.go
+++ b/internal/mode/static/state/conditions/conditions.go
@@ -87,6 +87,10 @@ const (
// parametersRef resource does not exist.
GatewayClassReasonParamsRefNotFound v1.GatewayClassConditionReason = "ParametersRefNotFound"
+ // GatewayClassReasonParamsRefInvalid is used with the "GatewayClassResolvedRefs" condition when the
+ // parametersRef resource is invalid.
+ GatewayClassReasonParamsRefInvalid v1.GatewayClassConditionReason = "ParametersRefInvalid"
+
// PolicyReasonNginxProxyConfigNotSet is used with the "PolicyAccepted" condition when the
// NginxProxy resource is missing or invalid.
PolicyReasonNginxProxyConfigNotSet v1alpha2.PolicyConditionReason = "NginxProxyConfigNotSet"
@@ -106,6 +110,21 @@ const (
// GatewayIgnoredReason is used with v1.RouteConditionAccepted when the route references a Gateway that is ignored
// by NGF.
GatewayIgnoredReason v1.RouteConditionReason = "GatewayIgnored"
+
+ // GatewayResolvedRefs condition indicates whether the controller was able to resolve the
+ // parametersRef on the Gateway.
+ GatewayResolvedRefs v1.GatewayConditionType = "ResolvedRefs"
+
+ // GatewayReasonResolvedRefs is used with the "GatewayResolvedRefs" condition when the condition is true.
+ GatewayReasonResolvedRefs v1.GatewayConditionReason = "ResolvedRefs"
+
+ // GatewayReasonParamsRefNotFound is used with the "GatewayResolvedRefs" condition when the
+ // parametersRef resource does not exist.
+ GatewayReasonParamsRefNotFound v1.GatewayConditionReason = "ParametersRefNotFound"
+
+ // GatewayReasonParamsRefInvalid is used with the "GatewayResolvedRefs" condition when the
+ // parametersRef resource is invalid.
+ GatewayReasonParamsRefInvalid v1.GatewayConditionReason = "ParametersRefInvalid"
)
// NewRouteNotAcceptedGatewayIgnored returns a Condition that indicates that the Route is not accepted by the Gateway
@@ -514,7 +533,7 @@ func NewGatewayClassResolvedRefs() conditions.Condition {
Type: string(GatewayClassResolvedRefs),
Status: metav1.ConditionTrue,
Reason: string(GatewayClassReasonResolvedRefs),
- Message: "parametersRef resource is resolved",
+ Message: "ParametersRef resource is resolved",
}
}
@@ -525,7 +544,18 @@ func NewGatewayClassRefNotFound() conditions.Condition {
Type: string(GatewayClassResolvedRefs),
Status: metav1.ConditionFalse,
Reason: string(GatewayClassReasonParamsRefNotFound),
- Message: "parametersRef resource could not be found",
+ Message: "ParametersRef resource could not be found",
+ }
+}
+
+// NewGatewayClassRefInvalid returns a Condition that indicates that the parametersRef
+// on the GatewayClass could not be resolved because the resource it references is invalid.
+func NewGatewayClassRefInvalid(msg string) conditions.Condition {
+ return conditions.Condition{
+ Type: string(GatewayClassResolvedRefs),
+ Status: metav1.ConditionFalse,
+ Reason: string(GatewayClassReasonParamsRefInvalid),
+ Message: msg,
}
}
@@ -537,7 +567,7 @@ func NewGatewayClassInvalidParameters(msg string) conditions.Condition {
Type: string(v1.GatewayClassConditionStatusAccepted),
Status: metav1.ConditionTrue,
Reason: string(v1.GatewayClassReasonInvalidParameters),
- Message: fmt.Sprintf("GatewayClass is accepted, but parametersRef is ignored due to an error: %s", msg),
+ Message: fmt.Sprintf("GatewayClass is accepted, but ParametersRef is ignored due to an error: %s", msg),
}
}
@@ -684,6 +714,51 @@ func NewNginxGatewayInvalid(msg string) conditions.Condition {
}
}
+// NewGatewayResolvedRefs returns a Condition that indicates that the parametersRef
+// on the Gateway is resolved.
+func NewGatewayResolvedRefs() conditions.Condition {
+ return conditions.Condition{
+ Type: string(GatewayResolvedRefs),
+ Status: metav1.ConditionTrue,
+ Reason: string(GatewayReasonResolvedRefs),
+ Message: "ParametersRef resource is resolved",
+ }
+}
+
+// NewGatewayRefNotFound returns a Condition that indicates that the parametersRef
+// on the Gateway could not be resolved.
+func NewGatewayRefNotFound() conditions.Condition {
+ return conditions.Condition{
+ Type: string(GatewayResolvedRefs),
+ Status: metav1.ConditionFalse,
+ Reason: string(GatewayReasonParamsRefNotFound),
+ Message: "ParametersRef resource could not be found",
+ }
+}
+
+// NewGatewayRefInvalid returns a Condition that indicates that the parametersRef
+// on the Gateway could not be resolved because the referenced resource is invalid.
+func NewGatewayRefInvalid(msg string) conditions.Condition {
+ return conditions.Condition{
+ Type: string(GatewayResolvedRefs),
+ Status: metav1.ConditionFalse,
+ Reason: string(GatewayReasonParamsRefInvalid),
+ Message: msg,
+ }
+}
+
+// NewGatewayInvalidParameters returns a Condition that indicates that the Gateway has invalid parameters.
+// We are allowing Accepted to still be true to prevent nullifying the entire Gateway config if a parametersRef
+// is updated to something invalid.
+func NewGatewayInvalidParameters(msg string) conditions.Condition {
+ return conditions.Condition{
+ Type: string(v1.GatewayConditionAccepted),
+ Status: metav1.ConditionTrue,
+ Reason: string(v1.GatewayReasonInvalidParameters),
+ Message: fmt.Sprintf("Gateway is accepted, but ParametersRef is ignored due to an error: %s", msg),
+ }
+}
+
// NewPolicyAccepted returns a Condition that indicates that the Policy is accepted.
func NewPolicyAccepted() conditions.Condition {
return conditions.Condition{
diff --git a/internal/mode/static/state/dataplane/configuration.go b/internal/mode/static/state/dataplane/configuration.go
index cafcbc0db8..4eb8ef80fe 100644
--- a/internal/mode/static/state/dataplane/configuration.go
+++ b/internal/mode/static/state/dataplane/configuration.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/base64"
"fmt"
+ "slices"
"sort"
apiv1 "k8s.io/api/core/v1"
@@ -13,7 +14,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
v1 "sigs.k8s.io/gateway-api/apis/v1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/config/policies"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/graph"
@@ -62,7 +64,7 @@ func BuildConfiguration(
Telemetry: buildTelemetry(g),
BaseHTTPConfig: baseHTTPConfig,
Logging: buildLogging(g),
- MainSnippets: buildSnippetsForContext(g.SnippetsFilters, ngfAPI.NginxContextMain),
+ MainSnippets: buildSnippetsForContext(g.SnippetsFilters, ngfAPIv1alpha1.NginxContextMain),
AuxiliarySecrets: buildAuxiliarySecrets(g.PlusSecrets),
}
@@ -773,22 +775,42 @@ func generateCertBundleID(configMap types.NamespacedName) CertBundleID {
return CertBundleID(fmt.Sprintf("cert_bundle_%s_%s", configMap.Namespace, configMap.Name))
}
+func telemetryEnabled(gw *graph.Gateway) bool {
+ if gw == nil {
+ return false
+ }
+
+ if gw.EffectiveNginxProxy == nil || gw.EffectiveNginxProxy.Telemetry == nil {
+ return false
+ }
+
+ tel := gw.EffectiveNginxProxy.Telemetry
+
+ if slices.Contains(tel.DisabledFeatures, ngfAPIv1alpha2.DisableTracing) {
+ return false
+ }
+
+ if tel.Exporter == nil || tel.Exporter.Endpoint == nil {
+ return false
+ }
+
+ return true
+}
+
// buildTelemetry generates the Otel configuration.
func buildTelemetry(g *graph.Graph) Telemetry {
- if g.NginxProxy == nil || !g.NginxProxy.Valid ||
- g.NginxProxy.Source.Spec.Telemetry == nil ||
- g.NginxProxy.Source.Spec.Telemetry.Exporter == nil {
+ if !telemetryEnabled(g.Gateway) {
return Telemetry{}
}
serviceName := fmt.Sprintf("ngf:%s:%s", g.Gateway.Source.Namespace, g.Gateway.Source.Name)
- telemetry := g.NginxProxy.Source.Spec.Telemetry
+ telemetry := g.Gateway.EffectiveNginxProxy.Telemetry
if telemetry.ServiceName != nil {
serviceName = serviceName + ":" + *telemetry.ServiceName
}
tel := Telemetry{
- Endpoint: telemetry.Exporter.Endpoint,
+ Endpoint: *telemetry.Exporter.Endpoint, // safe to deref here since we verified that telemetry is enabled
ServiceName: serviceName,
}
@@ -809,7 +831,7 @@ func buildTelemetry(g *graph.Graph) Telemetry {
// logic in this function
ratioMap := make(map[string]int32)
for _, pol := range g.NGFPolicies {
- if obsPol, ok := pol.Source.(*ngfAPI.ObservabilityPolicy); ok {
+ if obsPol, ok := pol.Source.(*ngfAPIv1alpha1.ObservabilityPolicy); ok {
if obsPol.Spec.Tracing != nil && obsPol.Spec.Tracing.Ratio != nil && *obsPol.Spec.Tracing.Ratio > 0 {
ratioName := CreateRatioVarName(*obsPol.Spec.Tracing.Ratio)
ratioMap[ratioName] = *obsPol.Spec.Tracing.Ratio
@@ -825,7 +847,7 @@ func buildTelemetry(g *graph.Graph) Telemetry {
return tel
}
-func setSpanAttributes(spanAttributes []ngfAPI.SpanAttribute) []SpanAttribute {
+func setSpanAttributes(spanAttributes []ngfAPIv1alpha1.SpanAttribute) []SpanAttribute {
spanAttrs := make([]SpanAttribute, 0, len(spanAttributes))
for _, spanAttr := range spanAttributes {
sa := SpanAttribute{
@@ -850,50 +872,53 @@ func buildBaseHTTPConfig(g *graph.Graph) BaseHTTPConfig {
// HTTP2 should be enabled by default
HTTP2: true,
IPFamily: Dual,
- Snippets: buildSnippetsForContext(g.SnippetsFilters, ngfAPI.NginxContextHTTP),
+ Snippets: buildSnippetsForContext(g.SnippetsFilters, ngfAPIv1alpha1.NginxContextHTTP),
}
- if g.NginxProxy == nil || !g.NginxProxy.Valid {
+
+ // safe to access EffectiveNginxProxy since we only call this function when the Gateway is not nil.
+ np := g.Gateway.EffectiveNginxProxy
+ if np == nil {
return baseConfig
}
- if g.NginxProxy.Source.Spec.DisableHTTP2 {
+ if np.DisableHTTP2 != nil && *np.DisableHTTP2 {
baseConfig.HTTP2 = false
}
- if g.NginxProxy.Source.Spec.IPFamily != nil {
- switch *g.NginxProxy.Source.Spec.IPFamily {
- case ngfAPI.IPv4:
+ if np.IPFamily != nil {
+ switch *np.IPFamily {
+ case ngfAPIv1alpha2.IPv4:
baseConfig.IPFamily = IPv4
- case ngfAPI.IPv6:
+ case ngfAPIv1alpha2.IPv6:
baseConfig.IPFamily = IPv6
}
}
- if g.NginxProxy.Source.Spec.RewriteClientIP != nil {
- if g.NginxProxy.Source.Spec.RewriteClientIP.Mode != nil {
- switch *g.NginxProxy.Source.Spec.RewriteClientIP.Mode {
- case ngfAPI.RewriteClientIPModeProxyProtocol:
+ if np.RewriteClientIP != nil {
+ if np.RewriteClientIP.Mode != nil {
+ switch *np.RewriteClientIP.Mode {
+ case ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol:
baseConfig.RewriteClientIPSettings.Mode = RewriteIPModeProxyProtocol
- case ngfAPI.RewriteClientIPModeXForwardedFor:
+ case ngfAPIv1alpha2.RewriteClientIPModeXForwardedFor:
baseConfig.RewriteClientIPSettings.Mode = RewriteIPModeXForwardedFor
}
}
- if len(g.NginxProxy.Source.Spec.RewriteClientIP.TrustedAddresses) > 0 {
+ if len(np.RewriteClientIP.TrustedAddresses) > 0 {
baseConfig.RewriteClientIPSettings.TrustedAddresses = convertAddresses(
- g.NginxProxy.Source.Spec.RewriteClientIP.TrustedAddresses,
+ np.RewriteClientIP.TrustedAddresses,
)
}
- if g.NginxProxy.Source.Spec.RewriteClientIP.SetIPRecursively != nil {
- baseConfig.RewriteClientIPSettings.IPRecursive = *g.NginxProxy.Source.Spec.RewriteClientIP.SetIPRecursively
+ if np.RewriteClientIP.SetIPRecursively != nil {
+ baseConfig.RewriteClientIPSettings.IPRecursive = *np.RewriteClientIP.SetIPRecursively
}
}
return baseConfig
}
-func createSnippetName(nc ngfAPI.NginxContext, nsname types.NamespacedName) string {
+func createSnippetName(nc ngfAPIv1alpha1.NginxContext, nsname types.NamespacedName) string {
return fmt.Sprintf(
"SnippetsFilter_%s_%s_%s",
nc,
@@ -904,7 +929,7 @@ func createSnippetName(nc ngfAPI.NginxContext, nsname types.NamespacedName) stri
func buildSnippetsForContext(
snippetFilters map[types.NamespacedName]*graph.SnippetsFilter,
- nc ngfAPI.NginxContext,
+ nc ngfAPIv1alpha1.NginxContext,
) []Snippet {
if len(snippetFilters) == 0 {
return nil
@@ -950,7 +975,7 @@ func buildPolicies(graphPolicies []*graph.Policy) []policies.Policy {
return finalPolicies
}
-func convertAddresses(addresses []ngfAPI.Address) []string {
+func convertAddresses(addresses []ngfAPIv1alpha2.Address) []string {
trustedAddresses := make([]string, len(addresses))
for i, addr := range addresses {
trustedAddresses[i] = addr.Value
@@ -961,10 +986,14 @@ func convertAddresses(addresses []ngfAPI.Address) []string {
func buildLogging(g *graph.Graph) Logging {
logSettings := Logging{ErrorLevel: defaultErrorLogLevel}
- ngfProxy := g.NginxProxy
- if ngfProxy != nil && ngfProxy.Source.Spec.Logging != nil {
- if ngfProxy.Source.Spec.Logging.ErrorLevel != nil {
- logSettings.ErrorLevel = string(*ngfProxy.Source.Spec.Logging.ErrorLevel)
+ if g.Gateway == nil || g.Gateway.EffectiveNginxProxy == nil {
+ return logSettings
+ }
+
+ ngfProxy := g.Gateway.EffectiveNginxProxy
+ if ngfProxy.Logging != nil {
+ if ngfProxy.Logging.ErrorLevel != nil {
+ logSettings.ErrorLevel = string(*ngfProxy.Logging.ErrorLevel)
}
}
diff --git a/internal/mode/static/state/dataplane/configuration_test.go b/internal/mode/static/state/dataplane/configuration_test.go
index 037bcd7d9d..3c61ed0ff3 100644
--- a/internal/mode/static/state/dataplane/configuration_test.go
+++ b/internal/mode/static/state/dataplane/configuration_test.go
@@ -19,7 +19,8 @@ import (
"sigs.k8s.io/gateway-api/apis/v1alpha2"
"sigs.k8s.io/gateway-api/apis/v1alpha3"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/config/policies"
@@ -337,7 +338,7 @@ func TestBuildConfiguration(t *testing.T) {
)
sf1 := &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "sf",
Namespace: "test",
@@ -345,16 +346,16 @@ func TestBuildConfiguration(t *testing.T) {
},
Valid: true,
Referenced: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTPServerLocation: "location snippet",
- ngfAPI.NginxContextHTTPServer: "server snippet",
- ngfAPI.NginxContextMain: "main snippet",
- ngfAPI.NginxContextHTTP: "http snippet",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation: "location snippet",
+ ngfAPIv1alpha1.NginxContextHTTPServer: "server snippet",
+ ngfAPIv1alpha1.NginxContextMain: "main snippet",
+ ngfAPIv1alpha1.NginxContextHTTP: "http snippet",
},
}
sfNotReferenced := &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "sf-not-referenced",
Namespace: "test",
@@ -362,9 +363,9 @@ func TestBuildConfiguration(t *testing.T) {
},
Valid: true,
Referenced: false,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextMain: "main snippet no ref",
- ngfAPI.NginxContextHTTP: "http snippet no ref",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextMain: "main snippet no ref",
+ ngfAPIv1alpha1.NginxContextHTTP: "http snippet no ref",
},
}
@@ -377,7 +378,7 @@ func TestBuildConfiguration(t *testing.T) {
extRefFilter := graph.Filter{
FilterType: graph.FilterExtensionRef,
ExtensionRef: &v1.LocalObjectReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.SnippetsFilter,
Name: "sf",
},
@@ -393,14 +394,14 @@ func TestBuildConfiguration(t *testing.T) {
expExtRefFilter := SnippetsFilter{
LocationSnippet: &Snippet{
Name: createSnippetName(
- ngfAPI.NginxContextHTTPServerLocation,
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation,
client.ObjectKeyFromObject(extRefFilter.ResolvedExtensionRef.SnippetsFilter.Source),
),
Contents: "location snippet",
},
ServerSnippet: &Snippet{
Name: createSnippetName(
- ngfAPI.NginxContextHTTPServer,
+ ngfAPIv1alpha1.NginxContextHTTPServer,
client.ObjectKeyFromObject(extRefFilter.ResolvedExtensionRef.SnippetsFilter.Source),
),
Contents: "server snippet",
@@ -825,43 +826,26 @@ func TestBuildConfiguration(t *testing.T) {
},
}
- nginxProxy := &graph.NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- Exporter: &ngfAPI.TelemetryExporter{
- Endpoint: "my-otel.svc:4563",
- BatchSize: helpers.GetPointer(int32(512)),
- BatchCount: helpers.GetPointer(int32(4)),
- Interval: helpers.GetPointer(ngfAPI.Duration("5s")),
- },
- ServiceName: helpers.GetPointer("my-svc"),
- },
- DisableHTTP2: true,
- IPFamily: helpers.GetPointer(ngfAPI.Dual),
+ nginxProxy := &graph.EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("my-otel.svc:4563"),
+ BatchSize: helpers.GetPointer(int32(512)),
+ BatchCount: helpers.GetPointer(int32(4)),
+ Interval: helpers.GetPointer(ngfAPIv1alpha1.Duration("5s")),
},
+ ServiceName: helpers.GetPointer("my-svc"),
},
- Valid: true,
+ DisableHTTP2: helpers.GetPointer(true),
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
}
- nginxProxyIPv4 := &graph.NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{},
- IPFamily: helpers.GetPointer(ngfAPI.IPv4),
- },
- },
- Valid: true,
+ nginxProxyIPv4 := &graph.EffectiveNginxProxy{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.IPv4),
}
- nginxProxyIPv6 := &graph.NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{},
- IPFamily: helpers.GetPointer(ngfAPI.IPv6),
- },
- },
- Valid: true,
+ nginxProxyIPv6 := &graph.EffectiveNginxProxy{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.IPv6),
}
tests := []struct {
@@ -2056,7 +2040,7 @@ func TestBuildConfiguration(t *testing.T) {
Valid: true,
Routes: map[graph.RouteKey]*graph.L7Route{},
})
- g.NginxProxy = nginxProxy
+ g.Gateway.EffectiveNginxProxy = nginxProxy
return g
}),
expConf: getModifiedExpectedConfiguration(func(conf Configuration) Configuration {
@@ -2074,42 +2058,7 @@ func TestBuildConfiguration(t *testing.T) {
conf.BaseHTTPConfig = BaseHTTPConfig{HTTP2: false, IPFamily: Dual}
return conf
}),
- msg: "NginxProxy with tracing config and http2 disabled",
- },
- {
- graph: getModifiedGraph(func(g *graph.Graph) *graph.Graph {
- g.Gateway.Source.ObjectMeta = metav1.ObjectMeta{
- Name: "gw",
- Namespace: "ns",
- }
- g.Gateway.Listeners = append(g.Gateway.Listeners, &graph.Listener{
- Name: "listener-80-1",
- Source: listener80,
- Valid: true,
- Routes: map[graph.RouteKey]*graph.L7Route{},
- })
- g.NginxProxy = &graph.NginxProxy{
- Valid: false,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- DisableHTTP2: true,
- IPFamily: helpers.GetPointer(ngfAPI.Dual),
- Telemetry: &ngfAPI.Telemetry{
- Exporter: &ngfAPI.TelemetryExporter{
- Endpoint: "some-endpoint",
- },
- },
- },
- },
- }
- return g
- }),
- expConf: getModifiedExpectedConfiguration(func(conf Configuration) Configuration {
- conf.SSLServers = []VirtualServer{}
- conf.SSLKeyPairs = map[SSLKeyPairID]SSLKeyPair{}
- return conf
- }),
- msg: "invalid NginxProxy",
+ msg: "EffectiveNginxProxy with tracing config and http2 disabled",
},
{
graph: getModifiedGraph(func(g *graph.Graph) *graph.Graph {
@@ -2218,7 +2167,7 @@ func TestBuildConfiguration(t *testing.T) {
Valid: true,
Routes: map[graph.RouteKey]*graph.L7Route{},
})
- g.NginxProxy = nginxProxyIPv4
+ g.Gateway.EffectiveNginxProxy = nginxProxyIPv4
return g
}),
expConf: getModifiedExpectedConfiguration(func(conf Configuration) Configuration {
@@ -2227,7 +2176,7 @@ func TestBuildConfiguration(t *testing.T) {
conf.BaseHTTPConfig = BaseHTTPConfig{HTTP2: true, IPFamily: IPv4}
return conf
}),
- msg: "NginxProxy with IPv4 IPFamily and no routes",
+ msg: "GatewayClass has NginxProxy with IPv4 IPFamily and no routes",
},
{
graph: getModifiedGraph(func(g *graph.Graph) *graph.Graph {
@@ -2241,7 +2190,7 @@ func TestBuildConfiguration(t *testing.T) {
Valid: true,
Routes: map[graph.RouteKey]*graph.L7Route{},
})
- g.NginxProxy = nginxProxyIPv6
+ g.Gateway.EffectiveNginxProxy = nginxProxyIPv6
return g
}),
expConf: getModifiedExpectedConfiguration(func(conf Configuration) Configuration {
@@ -2250,7 +2199,7 @@ func TestBuildConfiguration(t *testing.T) {
conf.BaseHTTPConfig = BaseHTTPConfig{HTTP2: true, IPFamily: IPv6}
return conf
}),
- msg: "NginxProxy with IPv6 IPFamily and no routes",
+ msg: "GatewayClass has NginxProxy with IPv6 IPFamily and no routes",
},
{
graph: getModifiedGraph(func(g *graph.Graph) *graph.Graph {
@@ -2264,21 +2213,16 @@ func TestBuildConfiguration(t *testing.T) {
Valid: true,
Routes: map[graph.RouteKey]*graph.L7Route{},
})
- g.NginxProxy = &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
- SetIPRecursively: helpers.GetPointer(true),
- TrustedAddresses: []ngfAPI.Address{
- {
- Type: ngfAPI.CIDRAddressType,
- Value: "1.1.1.1/32",
- },
- },
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
+ g.Gateway.EffectiveNginxProxy = &graph.EffectiveNginxProxy{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ SetIPRecursively: helpers.GetPointer(true),
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
+ {
+ Type: ngfAPIv1alpha2.CIDRAddressType,
+ Value: "1.1.1.1/32",
},
},
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
},
}
return g
@@ -2297,7 +2241,7 @@ func TestBuildConfiguration(t *testing.T) {
}
return conf
}),
- msg: "NginxProxy with rewriteClientIP details set",
+ msg: "GatewayClass has NginxProxy with rewriteClientIP details set",
},
{
graph: getModifiedGraph(func(g *graph.Graph) *graph.Graph {
@@ -2311,12 +2255,9 @@ func TestBuildConfiguration(t *testing.T) {
Valid: true,
Routes: map[graph.RouteKey]*graph.L7Route{},
})
- g.NginxProxy = &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelDebug)},
- },
+ g.Gateway.EffectiveNginxProxy = &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelDebug),
},
}
return g
@@ -2327,7 +2268,7 @@ func TestBuildConfiguration(t *testing.T) {
conf.Logging = Logging{ErrorLevel: "debug"}
return conf
}),
- msg: "NginxProxy with error log level set to debug",
+ msg: "GatewayClass has NginxProxy with error log level set to debug",
},
{
graph: getModifiedGraph(func(g *graph.Graph) *graph.Graph {
@@ -2342,7 +2283,7 @@ func TestBuildConfiguration(t *testing.T) {
conf.MainSnippets = []Snippet{
{
Name: createSnippetName(
- ngfAPI.NginxContextMain,
+ ngfAPIv1alpha1.NginxContextMain,
client.ObjectKeyFromObject(sf1.Source),
),
Contents: "main snippet",
@@ -2351,7 +2292,7 @@ func TestBuildConfiguration(t *testing.T) {
conf.BaseHTTPConfig.Snippets = []Snippet{
{
Name: createSnippetName(
- ngfAPI.NginxContextHTTP,
+ ngfAPIv1alpha1.NginxContextHTTP,
client.ObjectKeyFromObject(sf1.Source),
),
Contents: "http snippet",
@@ -2534,14 +2475,14 @@ func TestCreateFilters(t *testing.T) {
snippetsFilter1 := graph.Filter{
FilterType: graph.FilterExtensionRef,
ExtensionRef: &v1.LocalObjectReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.SnippetsFilter,
Name: "sf1",
},
ResolvedExtensionRef: &graph.ExtensionRefFilter{
Valid: true,
SnippetsFilter: &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "sf1",
Namespace: "default",
@@ -2549,11 +2490,11 @@ func TestCreateFilters(t *testing.T) {
},
Valid: true,
Referenced: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTPServerLocation: "location snippet 1",
- ngfAPI.NginxContextMain: "main snippet 1",
- ngfAPI.NginxContextHTTPServer: "server snippet 1",
- ngfAPI.NginxContextHTTP: "http snippet 1",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation: "location snippet 1",
+ ngfAPIv1alpha1.NginxContextMain: "main snippet 1",
+ ngfAPIv1alpha1.NginxContextHTTPServer: "server snippet 1",
+ ngfAPIv1alpha1.NginxContextHTTP: "http snippet 1",
},
},
},
@@ -2562,14 +2503,14 @@ func TestCreateFilters(t *testing.T) {
snippetsFilter2 := graph.Filter{
FilterType: graph.FilterExtensionRef,
ExtensionRef: &v1.LocalObjectReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.SnippetsFilter,
Name: "sf2",
},
ResolvedExtensionRef: &graph.ExtensionRefFilter{
Valid: true,
SnippetsFilter: &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "sf2",
Namespace: "default",
@@ -2577,11 +2518,11 @@ func TestCreateFilters(t *testing.T) {
},
Valid: true,
Referenced: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTPServerLocation: "location snippet 2",
- ngfAPI.NginxContextMain: "main snippet 2",
- ngfAPI.NginxContextHTTPServer: "server snippet 2",
- ngfAPI.NginxContextHTTP: "http snippet 2",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation: "location snippet 2",
+ ngfAPIv1alpha1.NginxContextMain: "main snippet 2",
+ ngfAPIv1alpha1.NginxContextHTTPServer: "server snippet 2",
+ ngfAPIv1alpha1.NginxContextHTTP: "http snippet 2",
},
},
},
@@ -2628,14 +2569,14 @@ func TestCreateFilters(t *testing.T) {
{
LocationSnippet: &Snippet{
Name: createSnippetName(
- ngfAPI.NginxContextHTTPServerLocation,
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation,
types.NamespacedName{Namespace: "default", Name: "sf1"},
),
Contents: "location snippet 1",
},
ServerSnippet: &Snippet{
Name: createSnippetName(
- ngfAPI.NginxContextHTTPServer,
+ ngfAPIv1alpha1.NginxContextHTTPServer,
types.NamespacedName{Namespace: "default", Name: "sf1"},
),
Contents: "server snippet 1",
@@ -2644,14 +2585,14 @@ func TestCreateFilters(t *testing.T) {
{
LocationSnippet: &Snippet{
Name: createSnippetName(
- ngfAPI.NginxContextHTTPServerLocation,
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation,
types.NamespacedName{Namespace: "default", Name: "sf2"},
),
Contents: "location snippet 2",
},
ServerSnippet: &Snippet{
Name: createSnippetName(
- ngfAPI.NginxContextHTTPServer,
+ ngfAPIv1alpha1.NginxContextHTTPServer,
types.NamespacedName{Namespace: "default", Name: "sf2"},
),
Contents: "server snippet 2",
@@ -3277,24 +3218,19 @@ func TestConvertBackendTLS(t *testing.T) {
func TestBuildTelemetry(t *testing.T) {
t.Parallel()
- telemetryConfigured := &graph.NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- Exporter: &ngfAPI.TelemetryExporter{
- Endpoint: "my-otel.svc:4563",
- BatchSize: helpers.GetPointer(int32(512)),
- BatchCount: helpers.GetPointer(int32(4)),
- Interval: helpers.GetPointer(ngfAPI.Duration("5s")),
- },
- ServiceName: helpers.GetPointer("my-svc"),
- SpanAttributes: []ngfAPI.SpanAttribute{
- {Key: "key", Value: "value"},
- },
- },
+ telemetryConfigured := &graph.EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("my-otel.svc:4563"),
+ BatchSize: helpers.GetPointer(int32(512)),
+ BatchCount: helpers.GetPointer(int32(4)),
+ Interval: helpers.GetPointer(ngfAPIv1alpha1.Duration("5s")),
+ },
+ ServiceName: helpers.GetPointer("my-svc"),
+ SpanAttributes: []ngfAPIv1alpha1.SpanAttribute{
+ {Key: "key", Value: "value"},
},
},
- Valid: true,
}
createTelemetry := func() Telemetry {
@@ -3320,10 +3256,24 @@ func TestBuildTelemetry(t *testing.T) {
msg string
expTelemetry Telemetry
}{
+ {
+ g: &graph.Graph{},
+ expTelemetry: Telemetry{},
+ msg: "nil Gateway",
+ },
+ {
+ g: &graph.Graph{
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: nil,
+ },
+ },
+ expTelemetry: Telemetry{},
+ msg: "nil effective NginxProxy",
+ },
{
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Source: &ngfAPI.NginxProxy{},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{},
},
},
expTelemetry: Telemetry{},
@@ -3331,19 +3281,49 @@ func TestBuildTelemetry(t *testing.T) {
},
{
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- Exporter: &ngfAPI.TelemetryExporter{},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("my-otel.svc:4563"),
+ },
+ DisabledFeatures: []ngfAPIv1alpha2.DisableTelemetryFeature{
+ ngfAPIv1alpha2.DisableTracing,
},
},
},
- Valid: false,
},
},
expTelemetry: Telemetry{},
- msg: "Invalid NginxProxy configured",
+ msg: "Telemetry disabled explicitly",
+ },
+ {
+ g: &graph.Graph{
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: nil,
+ },
+ },
+ },
+ },
+ expTelemetry: Telemetry{},
+ msg: "Telemetry disabled implicitly (nil exporter)",
+ },
+ {
+ g: &graph.Graph{
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: nil,
+ },
+ },
+ },
+ },
+ },
+ expTelemetry: Telemetry{},
+ msg: "Telemetry disabled implicitly (nil exporter endpoint)",
},
{
g: &graph.Graph{
@@ -3354,8 +3334,8 @@ func TestBuildTelemetry(t *testing.T) {
Namespace: "ns",
},
},
+ EffectiveNginxProxy: telemetryConfigured,
},
- NginxProxy: telemetryConfigured,
},
expTelemetry: createTelemetry(),
msg: "Telemetry configured",
@@ -3369,17 +3349,17 @@ func TestBuildTelemetry(t *testing.T) {
Namespace: "ns",
},
},
+ EffectiveNginxProxy: telemetryConfigured,
},
- NginxProxy: telemetryConfigured,
NGFPolicies: map[graph.PolicyKey]*graph.Policy{
{NsName: types.NamespacedName{Name: "obsPolicy"}}: {
- Source: &ngfAPI.ObservabilityPolicy{
+ Source: &ngfAPIv1alpha1.ObservabilityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "obsPolicy",
Namespace: "custom-ns",
},
- Spec: ngfAPI.ObservabilityPolicySpec{
- Tracing: &ngfAPI.Tracing{
+ Spec: ngfAPIv1alpha1.ObservabilityPolicySpec{
+ Tracing: &ngfAPIv1alpha1.Tracing{
Ratio: helpers.GetPointer[int32](25),
},
},
@@ -3404,50 +3384,50 @@ func TestBuildTelemetry(t *testing.T) {
Namespace: "ns",
},
},
+ EffectiveNginxProxy: telemetryConfigured,
},
- NginxProxy: telemetryConfigured,
NGFPolicies: map[graph.PolicyKey]*graph.Policy{
{NsName: types.NamespacedName{Name: "obsPolicy"}}: {
- Source: &ngfAPI.ObservabilityPolicy{
+ Source: &ngfAPIv1alpha1.ObservabilityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "obsPolicy",
Namespace: "custom-ns",
},
- Spec: ngfAPI.ObservabilityPolicySpec{
- Tracing: &ngfAPI.Tracing{
+ Spec: ngfAPIv1alpha1.ObservabilityPolicySpec{
+ Tracing: &ngfAPIv1alpha1.Tracing{
Ratio: helpers.GetPointer[int32](25),
},
},
},
},
{NsName: types.NamespacedName{Name: "obsPolicy2"}}: {
- Source: &ngfAPI.ObservabilityPolicy{
+ Source: &ngfAPIv1alpha1.ObservabilityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "obsPolicy2",
Namespace: "custom-ns",
},
- Spec: ngfAPI.ObservabilityPolicySpec{
- Tracing: &ngfAPI.Tracing{
+ Spec: ngfAPIv1alpha1.ObservabilityPolicySpec{
+ Tracing: &ngfAPIv1alpha1.Tracing{
Ratio: helpers.GetPointer[int32](50),
},
},
},
},
{NsName: types.NamespacedName{Name: "obsPolicy3"}}: {
- Source: &ngfAPI.ObservabilityPolicy{
+ Source: &ngfAPIv1alpha1.ObservabilityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "obsPolicy3",
Namespace: "custom-ns",
},
- Spec: ngfAPI.ObservabilityPolicySpec{
- Tracing: &ngfAPI.Tracing{
+ Spec: ngfAPIv1alpha1.ObservabilityPolicySpec{
+ Tracing: &ngfAPIv1alpha1.Tracing{
Ratio: helpers.GetPointer[int32](25),
},
},
},
},
{NsName: types.NamespacedName{Name: "csPolicy"}}: {
- Source: &ngfAPI.ClientSettingsPolicy{
+ Source: &ngfAPIv1alpha1.ClientSettingsPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "csPolicy",
Namespace: "custom-ns",
@@ -3474,17 +3454,17 @@ func TestBuildTelemetry(t *testing.T) {
Namespace: "ns",
},
},
+ EffectiveNginxProxy: telemetryConfigured,
},
- NginxProxy: telemetryConfigured,
NGFPolicies: map[graph.PolicyKey]*graph.Policy{
{NsName: types.NamespacedName{Name: "obsPolicy"}}: {
- Source: &ngfAPI.ObservabilityPolicy{
+ Source: &ngfAPIv1alpha1.ObservabilityPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "obsPolicy",
Namespace: "custom-ns",
},
- Spec: ngfAPI.ObservabilityPolicySpec{
- Tracing: &ngfAPI.Tracing{
+ Spec: ngfAPIv1alpha1.ObservabilityPolicySpec{
+ Tracing: &ngfAPIv1alpha1.Tracing{
Ratio: helpers.GetPointer[int32](0),
},
},
@@ -3911,9 +3891,8 @@ func TestBuildRewriteIPSettings(t *testing.T) {
{
msg: "no rewrite IP settings configured",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{},
},
},
expRewriteIPSettings: RewriteClientIPSettings{},
@@ -3921,20 +3900,17 @@ func TestBuildRewriteIPSettings(t *testing.T) {
{
msg: "rewrite IP settings configured with proxyProtocol",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
- TrustedAddresses: []ngfAPI.Address{
- {
- Type: ngfAPI.CIDRAddressType,
- Value: "10.9.9.4/32",
- },
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
+ {
+ Type: ngfAPIv1alpha2.CIDRAddressType,
+ Value: "10.9.9.4/32",
},
- SetIPRecursively: helpers.GetPointer(true),
},
+ SetIPRecursively: helpers.GetPointer(true),
},
},
},
@@ -3948,20 +3924,17 @@ func TestBuildRewriteIPSettings(t *testing.T) {
{
msg: "rewrite IP settings configured with xForwardedFor",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeXForwardedFor),
- TrustedAddresses: []ngfAPI.Address{
- {
- Type: ngfAPI.CIDRAddressType,
- Value: "76.89.90.11/24",
- },
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeXForwardedFor),
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
+ {
+ Type: ngfAPIv1alpha2.CIDRAddressType,
+ Value: "76.89.90.11/24",
},
- SetIPRecursively: helpers.GetPointer(true),
},
+ SetIPRecursively: helpers.GetPointer(true),
},
},
},
@@ -3975,32 +3948,29 @@ func TestBuildRewriteIPSettings(t *testing.T) {
{
msg: "rewrite IP settings configured with recursive set to false and multiple trusted addresses",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeXForwardedFor),
- TrustedAddresses: []ngfAPI.Address{
- {
- Type: ngfAPI.CIDRAddressType,
- Value: "5.5.5.5/12",
- },
- {
- Type: ngfAPI.CIDRAddressType,
- Value: "1.1.1.1/26",
- },
- {
- Type: ngfAPI.CIDRAddressType,
- Value: "2.2.2.2/32",
- },
- {
- Type: ngfAPI.CIDRAddressType,
- Value: "3.3.3.3/24",
- },
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeXForwardedFor),
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
+ {
+ Type: ngfAPIv1alpha2.CIDRAddressType,
+ Value: "5.5.5.5/12",
+ },
+ {
+ Type: ngfAPIv1alpha2.CIDRAddressType,
+ Value: "1.1.1.1/26",
+ },
+ {
+ Type: ngfAPIv1alpha2.CIDRAddressType,
+ Value: "2.2.2.2/32",
+ },
+ {
+ Type: ngfAPIv1alpha2.CIDRAddressType,
+ Value: "3.3.3.3/24",
},
- SetIPRecursively: helpers.GetPointer(false),
},
+ SetIPRecursively: helpers.GetPointer(false),
},
},
},
@@ -4033,30 +4003,39 @@ func TestBuildLogging(t *testing.T) {
expLoggingSettings Logging
}{
{
- msg: "NginxProxy is nil",
- g: &graph.Graph{},
+ msg: "Gateway is nil",
+ g: &graph.Graph{
+ Gateway: nil,
+ },
expLoggingSettings: defaultLogging,
},
{
- msg: "NginxProxy does not specify log level",
+ msg: "Gateway has no effective NginxProxy",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: nil,
+ },
+ },
+ expLoggingSettings: defaultLogging,
+ },
+ {
+ msg: "Effective NginxProxy does not specify log level",
+ g: &graph.Graph{
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
},
},
},
expLoggingSettings: defaultLogging,
},
{
- msg: "NginxProxy log level set to debug",
+ msg: "Effective NginxProxy log level set to debug",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelDebug)},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelDebug),
},
},
},
@@ -4064,13 +4043,12 @@ func TestBuildLogging(t *testing.T) {
expLoggingSettings: Logging{ErrorLevel: "debug"},
},
{
- msg: "NginxProxy log level set to info",
+ msg: "Effective NginxProxy log level set to info",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelInfo)},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelInfo),
},
},
},
@@ -4078,13 +4056,12 @@ func TestBuildLogging(t *testing.T) {
expLoggingSettings: Logging{ErrorLevel: defaultErrorLogLevel},
},
{
- msg: "NginxProxy log level set to notice",
+ msg: "Effective NginxProxy log level set to notice",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelNotice)},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelNotice),
},
},
},
@@ -4092,13 +4069,12 @@ func TestBuildLogging(t *testing.T) {
expLoggingSettings: Logging{ErrorLevel: "notice"},
},
{
- msg: "NginxProxy log level set to warn",
+ msg: "Effective NginxProxy log level set to warn",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelWarn)},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelWarn),
},
},
},
@@ -4106,13 +4082,12 @@ func TestBuildLogging(t *testing.T) {
expLoggingSettings: Logging{ErrorLevel: "warn"},
},
{
- msg: "NginxProxy log level set to error",
+ msg: "Effective NginxProxy log level set to error",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelError)},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError),
},
},
},
@@ -4120,13 +4095,12 @@ func TestBuildLogging(t *testing.T) {
expLoggingSettings: Logging{ErrorLevel: "error"},
},
{
- msg: "NginxProxy log level set to crit",
+ msg: "Effective NginxProxy log level set to crit",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelCrit)},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelCrit),
},
},
},
@@ -4134,13 +4108,12 @@ func TestBuildLogging(t *testing.T) {
expLoggingSettings: Logging{ErrorLevel: "crit"},
},
{
- msg: "NginxProxy log level set to alert",
+ msg: "Effective NginxProxy log level set to alert",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelAlert)},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelAlert),
},
},
},
@@ -4148,13 +4121,12 @@ func TestBuildLogging(t *testing.T) {
expLoggingSettings: Logging{ErrorLevel: "alert"},
},
{
- msg: "NginxProxy log level set to emerg",
+ msg: "Effective NginxProxy log level set to emerg",
g: &graph.Graph{
- NginxProxy: &graph.NginxProxy{
- Valid: true,
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelEmerg)},
+ Gateway: &graph.Gateway{
+ EffectiveNginxProxy: &graph.EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelEmerg),
},
},
},
@@ -4179,7 +4151,7 @@ func TestCreateSnippetName(t *testing.T) {
g := NewWithT(t)
name := createSnippetName(
- ngfAPI.NginxContextHTTPServerLocation,
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation,
types.NamespacedName{Namespace: "some-ns", Name: "some-name"},
)
g.Expect(name).To(Equal("SnippetsFilter_http.server.location_some-ns_some-name"))
@@ -4189,7 +4161,7 @@ func TestBuildSnippetForContext(t *testing.T) {
t.Parallel()
validUnreferenced := &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "valid-unreferenced",
Namespace: "default",
@@ -4197,13 +4169,13 @@ func TestBuildSnippetForContext(t *testing.T) {
},
Valid: true,
Referenced: false,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTPServerLocation: "valid unreferenced",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation: "valid unreferenced",
},
}
invalidUnreferenced := &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "invalid-unreferenced",
Namespace: "default",
@@ -4211,13 +4183,13 @@ func TestBuildSnippetForContext(t *testing.T) {
},
Valid: false,
Referenced: false,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTPServerLocation: "invalid unreferenced",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation: "invalid unreferenced",
},
}
invalidReferenced := &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "invalid-referenced",
Namespace: "default",
@@ -4225,13 +4197,13 @@ func TestBuildSnippetForContext(t *testing.T) {
},
Valid: false,
Referenced: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTPServerLocation: "invalid referenced",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation: "invalid referenced",
},
}
validReferenced1 := &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "valid-referenced1",
Namespace: "default",
@@ -4239,14 +4211,14 @@ func TestBuildSnippetForContext(t *testing.T) {
},
Valid: true,
Referenced: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTP: "http valid referenced 1",
- ngfAPI.NginxContextMain: "main valid referenced 1",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTP: "http valid referenced 1",
+ ngfAPIv1alpha1.NginxContextMain: "main valid referenced 1",
},
}
validReferenced2 := &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "valid-referenced2",
Namespace: "other-ns",
@@ -4254,14 +4226,14 @@ func TestBuildSnippetForContext(t *testing.T) {
},
Valid: true,
Referenced: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextMain: "main valid referenced 2",
- ngfAPI.NginxContextHTTP: "http valid referenced 2",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextMain: "main valid referenced 2",
+ ngfAPIv1alpha1.NginxContextHTTP: "http valid referenced 2",
},
}
validReferenced3 := &graph.SnippetsFilter{
- Source: &ngfAPI.SnippetsFilter{
+ Source: &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "valid-referenced3",
Namespace: "other-ns",
@@ -4269,29 +4241,29 @@ func TestBuildSnippetForContext(t *testing.T) {
},
Valid: true,
Referenced: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTPServerLocation: "location valid referenced 2",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTPServerLocation: "location valid referenced 2",
},
}
expMainSnippets := []Snippet{
{
- Name: createSnippetName(ngfAPI.NginxContextMain, client.ObjectKeyFromObject(validReferenced1.Source)),
+ Name: createSnippetName(ngfAPIv1alpha1.NginxContextMain, client.ObjectKeyFromObject(validReferenced1.Source)),
Contents: "main valid referenced 1",
},
{
- Name: createSnippetName(ngfAPI.NginxContextMain, client.ObjectKeyFromObject(validReferenced2.Source)),
+ Name: createSnippetName(ngfAPIv1alpha1.NginxContextMain, client.ObjectKeyFromObject(validReferenced2.Source)),
Contents: "main valid referenced 2",
},
}
expHTTPSnippets := []Snippet{
{
- Name: createSnippetName(ngfAPI.NginxContextHTTP, client.ObjectKeyFromObject(validReferenced1.Source)),
+ Name: createSnippetName(ngfAPIv1alpha1.NginxContextHTTP, client.ObjectKeyFromObject(validReferenced1.Source)),
Contents: "http valid referenced 1",
},
{
- Name: createSnippetName(ngfAPI.NginxContextHTTP, client.ObjectKeyFromObject(validReferenced2.Source)),
+ Name: createSnippetName(ngfAPIv1alpha1.NginxContextHTTP, client.ObjectKeyFromObject(validReferenced2.Source)),
Contents: "http valid referenced 2",
},
}
@@ -4310,25 +4282,25 @@ func TestBuildSnippetForContext(t *testing.T) {
tests := []struct {
name string
snippetsFilters map[types.NamespacedName]*graph.SnippetsFilter
- ctx ngfAPI.NginxContext
+ ctx ngfAPIv1alpha1.NginxContext
expSnippets []Snippet
}{
{
name: "no snippets filters",
snippetsFilters: nil,
- ctx: ngfAPI.NginxContextMain,
+ ctx: ngfAPIv1alpha1.NginxContextMain,
expSnippets: nil,
},
{
name: "main context: mix of invalid, unreferenced, and valid, referenced snippets filters",
snippetsFilters: getSnippetsFilters(),
- ctx: ngfAPI.NginxContextMain,
+ ctx: ngfAPIv1alpha1.NginxContextMain,
expSnippets: expMainSnippets,
},
{
name: "http context: mix of invalid, unreferenced, and valid, referenced snippets filters",
snippetsFilters: getSnippetsFilters(),
- ctx: ngfAPI.NginxContextHTTP,
+ ctx: ngfAPIv1alpha1.NginxContextHTTP,
expSnippets: expHTTPSnippets,
},
}
diff --git a/internal/mode/static/state/graph/backend_refs.go b/internal/mode/static/state/graph/backend_refs.go
index e8c5120b48..683983cfd3 100644
--- a/internal/mode/static/state/graph/backend_refs.go
+++ b/internal/mode/static/state/graph/backend_refs.go
@@ -11,8 +11,7 @@ import (
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
"sigs.k8s.io/gateway-api/apis/v1alpha3"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
-
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/sort"
@@ -47,7 +46,7 @@ func addBackendRefsToRouteRules(
refGrantResolver *referenceGrantResolver,
services map[types.NamespacedName]*v1.Service,
backendTLSPolicies map[types.NamespacedName]*BackendTLSPolicy,
- npCfg *NginxProxy,
+ npCfg *EffectiveNginxProxy,
) {
for _, r := range routes {
addBackendRefsToRules(r, refGrantResolver, services, backendTLSPolicies, npCfg)
@@ -61,7 +60,7 @@ func addBackendRefsToRules(
refGrantResolver *referenceGrantResolver,
services map[types.NamespacedName]*v1.Service,
backendTLSPolicies map[types.NamespacedName]*BackendTLSPolicy,
- npCfg *NginxProxy,
+ npCfg *EffectiveNginxProxy,
) {
if !route.Valid {
return
@@ -123,7 +122,7 @@ func createBackendRef(
services map[types.NamespacedName]*v1.Service,
refPath *field.Path,
backendTLSPolicies map[types.NamespacedName]*BackendTLSPolicy,
- npCfg *NginxProxy,
+ npCfg *EffectiveNginxProxy,
) (BackendRef, *conditions.Condition) {
// Data plane will handle invalid ref by responding with 500.
// Because of that, we always need to add a BackendRef to group.Backends, even if the ref is invalid.
@@ -316,30 +315,32 @@ func getIPFamilyAndPortFromRef(
return svc.Spec.IPFamilies, svcPort, nil
}
-func verifyIPFamily(npCfg *NginxProxy, svcIPFamily []v1.IPFamily) error {
- if npCfg == nil || npCfg.Source == nil || !npCfg.Valid {
+func verifyIPFamily(npCfg *EffectiveNginxProxy, svcIPFamily []v1.IPFamily) error {
+ if npCfg == nil {
return nil
}
- // we can access this field since we have already validated that ipFamily is not nil in validateNginxProxy.
- npIPFamily := npCfg.Source.Spec.IPFamily
- if *npIPFamily == ngfAPI.IPv4 {
- if slices.Contains(svcIPFamily, v1.IPv6Protocol) {
- // capitalizing error message to match the rest of the error messages associated with a condition
- //nolint: stylecheck
- return errors.New(
- "Service configured with IPv6 family but NginxProxy is configured with IPv4",
- )
- }
+ containsIPv6 := slices.Contains(svcIPFamily, v1.IPv6Protocol)
+ containsIPv4 := slices.Contains(svcIPFamily, v1.IPv4Protocol)
+
+ //nolint: stylecheck // used in status condition which is normally capitalized
+ errIPv6Mismatch := errors.New("Service configured with IPv6 family but NginxProxy is configured with IPv4")
+ //nolint: stylecheck // used in status condition which is normally capitalized
+ errIPv4Mismatch := errors.New("Service configured with IPv4 family but NginxProxy is configured with IPv6")
+
+ npIPFamily := npCfg.IPFamily
+
+ if npIPFamily == nil {
+ // default is dual so we don't need to check the service IPFamily.
+ return nil
}
- if *npIPFamily == ngfAPI.IPv6 {
- if slices.Contains(svcIPFamily, v1.IPv4Protocol) {
- // capitalizing error message to match the rest of the error messages associated with a condition
- //nolint: stylecheck
- return errors.New(
- "Service configured with IPv4 family but NginxProxy is configured with IPv6",
- )
- }
+
+ if *npIPFamily == ngfAPIv1alpha2.IPv4 && containsIPv6 {
+ return errIPv6Mismatch
+ }
+
+ if *npIPFamily == ngfAPIv1alpha2.IPv6 && containsIPv4 {
+ return errIPv4Mismatch
}
return nil
diff --git a/internal/mode/static/state/graph/backend_refs_test.go b/internal/mode/static/state/graph/backend_refs_test.go
index b7c49648da..a0ebfbd9cd 100644
--- a/internal/mode/static/state/graph/backend_refs_test.go
+++ b/internal/mode/static/state/graph/backend_refs_test.go
@@ -14,7 +14,7 @@ import (
"sigs.k8s.io/gateway-api/apis/v1alpha2"
"sigs.k8s.io/gateway-api/apis/v1alpha3"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
staticConds "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/conditions"
@@ -324,55 +324,35 @@ func TestVerifyIPFamily(t *testing.T) {
test := []struct {
name string
expErr error
- npCfg *NginxProxy
+ npCfg *EffectiveNginxProxy
svcIPFamily []v1.IPFamily
}{
{
name: "Valid - IPv6 and IPv4 configured for NGINX, service has only IPv4",
- npCfg: &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- IPFamily: helpers.GetPointer(ngfAPI.Dual),
- },
- },
- Valid: true,
+ npCfg: &EffectiveNginxProxy{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
},
svcIPFamily: []v1.IPFamily{v1.IPv4Protocol},
},
{
name: "Valid - IPv6 and IPv4 configured for NGINX, service has only IPv6",
- npCfg: &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- IPFamily: helpers.GetPointer(ngfAPI.Dual),
- },
- },
- Valid: true,
+ npCfg: &EffectiveNginxProxy{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
},
svcIPFamily: []v1.IPFamily{v1.IPv6Protocol},
},
{
name: "Invalid - IPv4 configured for NGINX, service has only IPv6",
- npCfg: &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- IPFamily: helpers.GetPointer(ngfAPI.IPv4),
- },
- },
- Valid: true,
+ npCfg: &EffectiveNginxProxy{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.IPv4),
},
svcIPFamily: []v1.IPFamily{v1.IPv6Protocol},
expErr: errors.New("Service configured with IPv6 family but NginxProxy is configured with IPv4"),
},
{
name: "Invalid - IPv6 configured for NGINX, service has only IPv4",
- npCfg: &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- IPFamily: helpers.GetPointer(ngfAPI.IPv6),
- },
- },
- Valid: true,
+ npCfg: &EffectiveNginxProxy{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.IPv6),
},
svcIPFamily: []v1.IPFamily{v1.IPv4Protocol},
expErr: errors.New("Service configured with IPv4 family but NginxProxy is configured with IPv6"),
@@ -845,7 +825,7 @@ func TestCreateBackend(t *testing.T) {
tests := []struct {
expectedCondition *conditions.Condition
- nginxProxy *NginxProxy
+ nginxProxySpec *EffectiveNginxProxy
name string
expectedServicePortReference string
ref gatewayv1.HTTPBackendRef
@@ -958,12 +938,7 @@ func TestCreateBackend(t *testing.T) {
Weight: 5,
Valid: false,
},
- nginxProxy: &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{IPFamily: helpers.GetPointer(ngfAPI.IPv6)},
- },
- Valid: true,
- },
+ nginxProxySpec: &EffectiveNginxProxy{IPFamily: helpers.GetPointer(ngfAPIv1alpha2.IPv6)},
expectedCondition: helpers.GetPointer(
staticConds.NewRouteInvalidIPFamily(`Service configured with IPv4 family but NginxProxy is configured with IPv6`),
),
@@ -1042,7 +1017,7 @@ func TestCreateBackend(t *testing.T) {
services,
refPath,
policies,
- test.nginxProxy,
+ test.nginxProxySpec,
)
g.Expect(helpers.Diff(test.expectedBackend, backend)).To(BeEmpty())
diff --git a/internal/mode/static/state/graph/gateway.go b/internal/mode/static/state/graph/gateway.go
index 2b73b46be2..e487a74184 100644
--- a/internal/mode/static/state/graph/gateway.go
+++ b/internal/mode/static/state/graph/gateway.go
@@ -9,6 +9,7 @@ import (
v1 "sigs.k8s.io/gateway-api/apis/v1"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
+ "github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds"
ngfsort "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/sort"
staticConds "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/conditions"
)
@@ -17,6 +18,12 @@ import (
type Gateway struct {
// Source is the corresponding Gateway resource.
Source *v1.Gateway
+ // NginxProxy is the NginxProxy referenced by this Gateway.
+ NginxProxy *NginxProxy
+ /// EffectiveNginxProxy holds the result of merging the NginxProxySpec on this resource with the NginxProxySpec on
+ // the GatewayClass resource. This is the effective set of config that should be applied to the Gateway.
+ // If non-nil, then this config is valid.
+ EffectiveNginxProxy *EffectiveNginxProxy
// Listeners include the listeners of the Gateway.
Listeners []*Listener
// Conditions holds the conditions for the Gateway.
@@ -98,29 +105,91 @@ func buildGateway(
gc *GatewayClass,
refGrantResolver *referenceGrantResolver,
protectedPorts ProtectedPorts,
+ nps map[types.NamespacedName]*NginxProxy,
) *Gateway {
if gw == nil {
return nil
}
- conds := validateGateway(gw, gc)
+ var np *NginxProxy
+ if gw.Spec.Infrastructure != nil && gw.Spec.Infrastructure.ParametersRef != nil {
+ npName := types.NamespacedName{Namespace: gw.Namespace, Name: gw.Spec.Infrastructure.ParametersRef.Name}
+ np = nps[npName]
+ }
- if len(conds) > 0 {
+ var gcNp *NginxProxy
+ if gc != nil {
+ gcNp = gc.NginxProxy
+ }
+
+ effectiveNginxProxy := buildEffectiveNginxProxy(gcNp, np)
+
+ conds, valid := validateGateway(gw, gc, np)
+
+ if !valid {
return &Gateway{
- Source: gw,
- Valid: false,
- Conditions: conds,
+ Source: gw,
+ Valid: false,
+ NginxProxy: np,
+ EffectiveNginxProxy: effectiveNginxProxy,
+ Conditions: conds,
}
}
return &Gateway{
- Source: gw,
- Listeners: buildListeners(gw, secretResolver, refGrantResolver, protectedPorts),
- Valid: true,
+ Source: gw,
+ Listeners: buildListeners(gw, secretResolver, refGrantResolver, protectedPorts),
+ NginxProxy: np,
+ EffectiveNginxProxy: effectiveNginxProxy,
+ Valid: true,
+ Conditions: conds,
}
}
-func validateGateway(gw *v1.Gateway, gc *GatewayClass) []conditions.Condition {
+func validateGatewayParametersRef(npCfg *NginxProxy, ref v1.LocalParametersReference) []conditions.Condition {
+ var conds []conditions.Condition
+
+ path := field.NewPath("spec.infrastructure.parametersRef")
+
+ if _, ok := supportedParamKinds[string(ref.Kind)]; !ok {
+ err := field.NotSupported(path.Child("kind"), string(ref.Kind), []string{kinds.NginxProxy})
+ conds = append(
+ conds,
+ staticConds.NewGatewayRefInvalid(err.Error()),
+ staticConds.NewGatewayInvalidParameters(err.Error()),
+ )
+
+ return conds
+ }
+
+ if npCfg == nil {
+ conds = append(
+ conds,
+ staticConds.NewGatewayRefNotFound(),
+ staticConds.NewGatewayInvalidParameters(
+ field.NotFound(path.Child("name"), ref.Name).Error(),
+ ),
+ )
+
+ return conds
+ }
+
+ if !npCfg.Valid {
+ msg := npCfg.ErrMsgs.ToAggregate().Error()
+ conds = append(
+ conds,
+ staticConds.NewGatewayRefInvalid(msg),
+ staticConds.NewGatewayInvalidParameters(msg),
+ )
+
+ return conds
+ }
+
+ conds = append(conds, staticConds.NewGatewayResolvedRefs())
+ return conds
+}
+
+func validateGateway(gw *v1.Gateway, gc *GatewayClass, npCfg *NginxProxy) ([]conditions.Condition, bool) {
var conds []conditions.Condition
if gc == nil {
@@ -136,5 +205,17 @@ func validateGateway(gw *v1.Gateway, gc *GatewayClass) []conditions.Condition {
conds = append(conds, staticConds.NewGatewayUnsupportedValue(valErr.Error())...)
}
- return conds
+ valid := true
+ // we evaluate validity before validating parametersRef because an invalid parametersRef/NginxProxy does not
+ // invalidate the entire Gateway.
+ if len(conds) > 0 {
+ valid = false
+ }
+
+ if gw.Spec.Infrastructure != nil && gw.Spec.Infrastructure.ParametersRef != nil {
+ paramConds := validateGatewayParametersRef(npCfg, *gw.Spec.Infrastructure.ParametersRef)
+ conds = append(conds, paramConds...)
+ }
+
+ return conds, valid
}
diff --git a/internal/mode/static/state/graph/gateway_test.go b/internal/mode/static/state/graph/gateway_test.go
index 36021e6dc3..456c21e29a 100644
--- a/internal/mode/static/state/graph/gateway_test.go
+++ b/internal/mode/static/state/graph/gateway_test.go
@@ -8,10 +8,13 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/util/validation/field"
"sigs.k8s.io/controller-runtime/pkg/client"
v1 "sigs.k8s.io/gateway-api/apis/v1"
- v1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
+ "sigs.k8s.io/gateway-api/apis/v1beta1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
+ "github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds"
staticConds "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/conditions"
@@ -338,6 +341,7 @@ func TestBuildGateway(t *testing.T) {
)
type gatewayCfg struct {
+ ref *v1.LocalParametersReference
listeners []v1.Listener
addresses []v1.GatewayAddress
}
@@ -354,12 +358,64 @@ func TestBuildGateway(t *testing.T) {
Addresses: cfg.addresses,
},
}
+
+ if cfg.ref != nil {
+ lastCreatedGateway.Spec.Infrastructure = &v1.GatewayInfrastructure{
+ ParametersRef: cfg.ref,
+ }
+ }
return lastCreatedGateway
}
getLastCreatedGateway := func() *v1.Gateway {
return lastCreatedGateway
}
+ validGwNp := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "test",
+ Name: "valid-gw-np",
+ },
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError)},
+ },
+ }
+ validGwNpRef := &v1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: validGwNp.Name,
+ }
+ invalidGwNp := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "test",
+ Name: "invalid-gw-np",
+ },
+ }
+ invalidGwNpRef := &v1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: invalidGwNp.Name,
+ }
+ invalidKindRef := &v1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: "Invalid",
+ Name: "invalid-kind",
+ }
+ npDoesNotExistRef := &v1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: "does-not-exist",
+ }
+
+ validGcNp := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "test",
+ Name: "valid-gc-np",
+ },
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
+ },
+ }
+
validGC := &GatewayClass{
Valid: true,
}
@@ -367,6 +423,14 @@ func TestBuildGateway(t *testing.T) {
Valid: false,
}
+ validGCWithNp := &GatewayClass{
+ Valid: true,
+ NginxProxy: &NginxProxy{
+ Source: validGcNp,
+ Valid: true,
+ },
+ }
+
supportedKindsForListeners := []v1.RouteGroupKind{
{Kind: v1.Kind(kinds.HTTPRoute), Group: helpers.GetPointer[v1.Group](v1.GroupName)},
{Kind: v1.Kind(kinds.GRPCRoute), Group: helpers.GetPointer[v1.Group](v1.GroupName)},
@@ -509,6 +573,90 @@ func TestBuildGateway(t *testing.T) {
},
name: "valid https listener with cross-namespace secret; allowed by reference grant",
},
+ {
+ gateway: createGateway(gatewayCfg{listeners: []v1.Listener{foo80Listener1}, ref: validGwNpRef}),
+ gatewayClass: validGC,
+ expected: &Gateway{
+ Source: getLastCreatedGateway(),
+ Listeners: []*Listener{
+ {
+ Name: "foo-80-1",
+ Source: foo80Listener1,
+ Valid: true,
+ Attachable: true,
+ Routes: map[RouteKey]*L7Route{},
+ L4Routes: map[L4RouteKey]*L4Route{},
+ SupportedKinds: supportedKindsForListeners,
+ },
+ },
+ Valid: true,
+ NginxProxy: &NginxProxy{
+ Source: validGwNp,
+ Valid: true,
+ },
+ EffectiveNginxProxy: &EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError),
+ },
+ },
+ Conditions: []conditions.Condition{staticConds.NewGatewayResolvedRefs()},
+ },
+ name: "valid http listener with valid NginxProxy; GatewayClass has no NginxProxy",
+ },
+ {
+ gateway: createGateway(gatewayCfg{listeners: []v1.Listener{foo80Listener1}, ref: validGwNpRef}),
+ gatewayClass: validGCWithNp,
+ expected: &Gateway{
+ Source: getLastCreatedGateway(),
+ Listeners: []*Listener{
+ {
+ Name: "foo-80-1",
+ Source: foo80Listener1,
+ Valid: true,
+ Attachable: true,
+ Routes: map[RouteKey]*L7Route{},
+ L4Routes: map[L4RouteKey]*L4Route{},
+ SupportedKinds: supportedKindsForListeners,
+ },
+ },
+ Valid: true,
+ NginxProxy: &NginxProxy{
+ Source: validGwNp,
+ Valid: true,
+ },
+ EffectiveNginxProxy: &EffectiveNginxProxy{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError),
+ },
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
+ },
+ Conditions: []conditions.Condition{staticConds.NewGatewayResolvedRefs()},
+ },
+ name: "valid http listener with valid NginxProxy; GatewayClass has valid NginxProxy too",
+ },
+ {
+ gateway: createGateway(gatewayCfg{listeners: []v1.Listener{foo80Listener1}}),
+ gatewayClass: validGCWithNp,
+ expected: &Gateway{
+ Source: getLastCreatedGateway(),
+ Listeners: []*Listener{
+ {
+ Name: "foo-80-1",
+ Source: foo80Listener1,
+ Valid: true,
+ Attachable: true,
+ Routes: map[RouteKey]*L7Route{},
+ L4Routes: map[L4RouteKey]*L4Route{},
+ SupportedKinds: supportedKindsForListeners,
+ },
+ },
+ Valid: true,
+ EffectiveNginxProxy: &EffectiveNginxProxy{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
+ },
+ },
+ name: "valid http listener; GatewayClass has valid NginxProxy",
+ },
{
gateway: createGateway(gatewayCfg{listeners: []v1.Listener{crossNamespaceSecretListener}}),
gatewayClass: validGC,
@@ -1024,6 +1172,116 @@ func TestBuildGateway(t *testing.T) {
},
name: "https listener and tls listener with non overlapping hostnames",
},
+ {
+ gateway: createGateway(gatewayCfg{listeners: []v1.Listener{foo80Listener1}, ref: invalidKindRef}),
+ gatewayClass: validGC,
+ expected: &Gateway{
+ Source: getLastCreatedGateway(),
+ Listeners: []*Listener{
+ {
+ Name: "foo-80-1",
+ Source: foo80Listener1,
+ Valid: true,
+ Attachable: true,
+ Routes: map[RouteKey]*L7Route{},
+ L4Routes: map[L4RouteKey]*L4Route{},
+ SupportedKinds: supportedKindsForListeners,
+ },
+ },
+ Valid: true, // invalid parametersRef does not invalidate Gateway.
+ Conditions: []conditions.Condition{
+ staticConds.NewGatewayRefInvalid(
+ "spec.infrastructure.parametersRef.kind: Unsupported value: \"Invalid\": " +
+ "supported values: \"NginxProxy\"",
+ ),
+ staticConds.NewGatewayInvalidParameters(
+ "spec.infrastructure.parametersRef.kind: Unsupported value: \"Invalid\": " +
+ "supported values: \"NginxProxy\"",
+ ),
+ },
+ },
+ name: "invalid parameters ref kind",
+ },
+ {
+ gateway: createGateway(gatewayCfg{listeners: []v1.Listener{foo80Listener1}, ref: npDoesNotExistRef}),
+ gatewayClass: validGC,
+ expected: &Gateway{
+ Source: getLastCreatedGateway(),
+ Listeners: []*Listener{
+ {
+ Name: "foo-80-1",
+ Source: foo80Listener1,
+ Valid: true,
+ Attachable: true,
+ Routes: map[RouteKey]*L7Route{},
+ L4Routes: map[L4RouteKey]*L4Route{},
+ SupportedKinds: supportedKindsForListeners,
+ },
+ },
+ Valid: true, // invalid parametersRef does not invalidate Gateway.
+ Conditions: []conditions.Condition{
+ staticConds.NewGatewayRefNotFound(),
+ staticConds.NewGatewayInvalidParameters(
+ "spec.infrastructure.parametersRef.name: Not found: \"does-not-exist\"",
+ ),
+ },
+ },
+ name: "referenced NginxProxy doesn't exist",
+ },
+ {
+ gateway: createGateway(gatewayCfg{listeners: []v1.Listener{foo80Listener1}, ref: invalidGwNpRef}),
+ gatewayClass: validGC,
+ expected: &Gateway{
+ Source: getLastCreatedGateway(),
+ Listeners: []*Listener{
+ {
+ Name: "foo-80-1",
+ Source: foo80Listener1,
+ Valid: true,
+ Attachable: true,
+ Routes: map[RouteKey]*L7Route{},
+ L4Routes: map[L4RouteKey]*L4Route{},
+ SupportedKinds: supportedKindsForListeners,
+ },
+ },
+ Valid: true, // invalid NginxProxy does not invalidate Gateway.
+ NginxProxy: &NginxProxy{
+ Source: invalidGwNp,
+ ErrMsgs: field.ErrorList{
+ field.Required(field.NewPath("somePath"), "someField"), // fake error
+ },
+ Valid: false,
+ },
+ Conditions: []conditions.Condition{
+ staticConds.NewGatewayRefInvalid("somePath: Required value: someField"),
+ staticConds.NewGatewayInvalidParameters("somePath: Required value: someField"),
+ },
+ },
+ name: "invalid NginxProxy",
+ },
+ {
+ gateway: createGateway(
+ gatewayCfg{listeners: []v1.Listener{foo80Listener1, invalidProtocolListener}, ref: invalidGwNpRef},
+ ),
+ gatewayClass: invalidGC,
+ expected: &Gateway{
+ Source: getLastCreatedGateway(),
+ Valid: false,
+ NginxProxy: &NginxProxy{
+ Source: invalidGwNp,
+ ErrMsgs: field.ErrorList{
+ field.Required(field.NewPath("somePath"), "someField"), // fake error
+ },
+ Valid: false,
+ },
+ Conditions: append(
+ staticConds.NewGatewayInvalid("GatewayClass is invalid"),
+ staticConds.NewGatewayRefInvalid("somePath: Required value: someField"),
+ staticConds.NewGatewayInvalidParameters("somePath: Required value: someField"),
+ ),
+ },
+ name: "invalid gatewayclass and invalid NginxProxy",
+ },
}
secretResolver := newSecretResolver(
@@ -1032,12 +1290,106 @@ func TestBuildGateway(t *testing.T) {
client.ObjectKeyFromObject(secretDiffNamespace): secretDiffNamespace,
})
+ nginxProxies := map[types.NamespacedName]*NginxProxy{
+ client.ObjectKeyFromObject(validGwNp): {Valid: true, Source: validGwNp},
+ client.ObjectKeyFromObject(validGcNp): {Valid: true, Source: validGcNp},
+ client.ObjectKeyFromObject(invalidGwNp): {
+ Source: invalidGwNp,
+ ErrMsgs: append(field.ErrorList{}, field.Required(field.NewPath("somePath"), "someField")),
+ Valid: false,
+ },
+ }
+
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
g := NewWithT(t)
resolver := newReferenceGrantResolver(test.refGrants)
- result := buildGateway(test.gateway, secretResolver, test.gatewayClass, resolver, protectedPorts)
+ result := buildGateway(test.gateway, secretResolver, test.gatewayClass, resolver, protectedPorts, nginxProxies)
g.Expect(helpers.Diff(test.expected, result)).To(BeEmpty())
})
}
}
+
+func TestValidateGatewayParametersRef(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ np *NginxProxy
+ ref v1.LocalParametersReference
+ expConds []conditions.Condition
+ }{
+ {
+ name: "unsupported parameter ref kind",
+ ref: v1.LocalParametersReference{
+ Kind: "wrong-kind",
+ },
+ expConds: []conditions.Condition{
+ staticConds.NewGatewayRefInvalid(
+ "spec.infrastructure.parametersRef.kind: Unsupported value: \"wrong-kind\": " +
+ "supported values: \"NginxProxy\"",
+ ),
+ staticConds.NewGatewayInvalidParameters(
+ "spec.infrastructure.parametersRef.kind: Unsupported value: \"wrong-kind\": " +
+ "supported values: \"NginxProxy\"",
+ ),
+ },
+ },
+ {
+ name: "nil nginx proxy",
+ ref: v1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: "np",
+ },
+ expConds: []conditions.Condition{
+ staticConds.NewGatewayRefNotFound(),
+ staticConds.NewGatewayInvalidParameters("spec.infrastructure.parametersRef.name: Not found: \"np\""),
+ },
+ },
+ {
+ name: "invalid nginx proxy",
+ np: &NginxProxy{
+ Source: &ngfAPIv1alpha2.NginxProxy{},
+ ErrMsgs: field.ErrorList{
+ field.Required(field.NewPath("somePath"), "someField"), // fake error
+ },
+ Valid: false,
+ },
+ ref: v1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: "np",
+ },
+ expConds: []conditions.Condition{
+ staticConds.NewGatewayRefInvalid("somePath: Required value: someField"),
+ staticConds.NewGatewayInvalidParameters("somePath: Required value: someField"),
+ },
+ },
+ {
+ name: "valid",
+ np: &NginxProxy{
+ Source: &ngfAPIv1alpha2.NginxProxy{},
+ Valid: true,
+ },
+ ref: v1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: "np",
+ },
+ expConds: []conditions.Condition{
+ staticConds.NewGatewayResolvedRefs(),
+ },
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
+ g := NewWithT(t)
+
+ conds := validateGatewayParametersRef(test.np, test.ref)
+ g.Expect(conds).To(BeEquivalentTo(test.expConds))
+ })
+ }
+}
diff --git a/internal/mode/static/state/graph/gatewayclass.go b/internal/mode/static/state/graph/gatewayclass.go
index 9fc1f67259..95e7c684c8 100644
--- a/internal/mode/static/state/graph/gatewayclass.go
+++ b/internal/mode/static/state/graph/gatewayclass.go
@@ -1,8 +1,6 @@
package graph
import (
- "errors"
-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -19,6 +17,8 @@ import (
type GatewayClass struct {
// Source is the source resource.
Source *v1.GatewayClass
+ // NginxProxy is the NginxProxy resource referenced by this GatewayClass.
+ NginxProxy *NginxProxy
// Conditions include Conditions for the GatewayClass.
Conditions []conditions.Condition
// Valid shows whether the GatewayClass is valid.
@@ -34,7 +34,7 @@ type processedGatewayClasses struct {
// processGatewayClasses returns the "Winner" GatewayClass, which is defined in
// the command-line argument and references this controller, and a list of "Ignored" GatewayClasses
// that reference this controller, but are not named in the command-line argument.
-// Also returns a boolean that says whether or not the GatewayClass defined
+// Also returns a boolean that says whether the GatewayClass defined
// in the command-line argument exists, regardless of which controller it references.
func processGatewayClasses(
gcs map[types.NamespacedName]*v1.GatewayClass,
@@ -63,22 +63,66 @@ func processGatewayClasses(
func buildGatewayClass(
gc *v1.GatewayClass,
- npCfg *NginxProxy,
+ nps map[types.NamespacedName]*NginxProxy,
crdVersions map[types.NamespacedName]*metav1.PartialObjectMetadata,
) *GatewayClass {
if gc == nil {
return nil
}
- conds, valid := validateGatewayClass(gc, npCfg, crdVersions)
+ var np *NginxProxy
+ if gc.Spec.ParametersRef != nil {
+ np = getNginxProxyForGatewayClass(*gc.Spec.ParametersRef, nps)
+ }
+
+ conds, valid := validateGatewayClass(gc, np, crdVersions)
return &GatewayClass{
Source: gc,
+ NginxProxy: np,
Valid: valid,
Conditions: conds,
}
}
+func getNginxProxyForGatewayClass(
+ ref v1.ParametersReference,
+ nps map[types.NamespacedName]*NginxProxy,
+) *NginxProxy {
+ if ref.Namespace == nil {
+ return nil
+ }
+
+ npName := types.NamespacedName{Name: ref.Name, Namespace: string(*ref.Namespace)}
+
+ return nps[npName]
+}
+
+func validateGatewayClassParametersRef(path *field.Path, ref v1.ParametersReference) []conditions.Condition {
+ var errs field.ErrorList
+
+ if _, ok := supportedParamKinds[string(ref.Kind)]; !ok {
+ errs = append(
+ errs,
+ field.NotSupported(path.Child("kind"), string(ref.Kind), []string{kinds.NginxProxy}),
+ )
+ }
+
+ if ref.Namespace == nil {
+ errs = append(errs, field.Required(path.Child("namespace"), "ParametersRef must specify Namespace"))
+ }
+
+ if len(errs) > 0 {
+ msg := errs.ToAggregate().Error()
+ return []conditions.Condition{
+ staticConds.NewGatewayClassRefInvalid(msg),
+ staticConds.NewGatewayClassInvalidParameters(msg),
+ }
+ }
+
+ return nil
+}
+
func validateGatewayClass(
gc *v1.GatewayClass,
npCfg *NginxProxy,
@@ -86,28 +130,44 @@ func validateGatewayClass(
) ([]conditions.Condition, bool) {
var conds []conditions.Condition
- if gc.Spec.ParametersRef != nil {
- var err error
- path := field.NewPath("spec").Child("parametersRef")
- if _, ok := supportedParamKinds[string(gc.Spec.ParametersRef.Kind)]; !ok {
- err = field.NotSupported(path.Child("kind"), string(gc.Spec.ParametersRef.Kind), []string{kinds.NginxProxy})
- } else if npCfg == nil {
- err = field.NotFound(path.Child("name"), gc.Spec.ParametersRef.Name)
- conds = append(conds, staticConds.NewGatewayClassRefNotFound())
- } else if !npCfg.Valid {
- err = errors.New(npCfg.ErrMsgs.ToAggregate().Error())
- }
+ supportedVersionConds, versionsValid := gatewayclass.ValidateCRDVersions(crdVersions)
+ conds = append(conds, supportedVersionConds...)
- if err != nil {
- conds = append(conds, staticConds.NewGatewayClassInvalidParameters(err.Error()))
- } else {
- conds = append(conds, staticConds.NewGatewayClassResolvedRefs())
- }
+ if gc.Spec.ParametersRef == nil {
+ return conds, versionsValid
}
- supportedVersionConds, versionsValid := gatewayclass.ValidateCRDVersions(crdVersions)
+ path := field.NewPath("spec").Child("parametersRef")
+ refConds := validateGatewayClassParametersRef(path, *gc.Spec.ParametersRef)
+
+ // return early since parametersRef isn't valid
+ if len(refConds) > 0 {
+ conds = append(conds, refConds...)
+ return conds, versionsValid
+ }
+
+ if npCfg == nil {
+ conds = append(
+ conds,
+ staticConds.NewGatewayClassRefNotFound(),
+ staticConds.NewGatewayClassInvalidParameters(
+ field.NotFound(path.Child("name"), gc.Spec.ParametersRef.Name).Error(),
+ ),
+ )
+ return conds, versionsValid
+ }
+
+ if !npCfg.Valid {
+ msg := npCfg.ErrMsgs.ToAggregate().Error()
+ conds = append(
+ conds,
+ staticConds.NewGatewayClassRefInvalid(msg),
+ staticConds.NewGatewayClassInvalidParameters(msg),
+ )
+ return conds, versionsValid
+ }
- return append(conds, supportedVersionConds...), versionsValid
+ return append(conds, staticConds.NewGatewayClassResolvedRefs()), versionsValid
}
var supportedParamKinds = map[string]struct{}{
diff --git a/internal/mode/static/state/graph/gatewayclass_test.go b/internal/mode/static/state/graph/gatewayclass_test.go
index 35e7f04764..c765047e24 100644
--- a/internal/mode/static/state/graph/gatewayclass_test.go
+++ b/internal/mode/static/state/graph/gatewayclass_test.go
@@ -10,7 +10,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
v1 "sigs.k8s.io/gateway-api/apis/v1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/gatewayclass"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
@@ -127,17 +127,32 @@ func TestProcessGatewayClasses(t *testing.T) {
func TestBuildGatewayClass(t *testing.T) {
t.Parallel()
validGC := &v1.GatewayClass{}
+ npNsName := types.NamespacedName{Namespace: "test", Name: "nginx-proxy"}
+
+ np := &ngfAPIv1alpha2.NginxProxy{
+ TypeMeta: metav1.TypeMeta{
+ Kind: kinds.NginxProxy,
+ },
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ ServiceName: helpers.GetPointer("my-svc"),
+ },
+ },
+ }
gcWithParams := &v1.GatewayClass{
Spec: v1.GatewayClassSpec{
ParametersRef: &v1.ParametersReference{
Kind: v1.Kind(kinds.NginxProxy),
- Namespace: helpers.GetPointer(v1.Namespace("test")),
- Name: "nginx-proxy",
+ Namespace: helpers.GetPointer(v1.Namespace(npNsName.Namespace)),
+ Name: npNsName.Name,
},
},
}
+ gcWithParamsNoNamespace := gcWithParams.DeepCopy()
+ gcWithParamsNoNamespace.Spec.ParametersRef.Namespace = nil
+
gcWithInvalidKind := &v1.GatewayClass{
Spec: v1.GatewayClassSpec{
ParametersRef: &v1.ParametersReference{
@@ -168,12 +183,11 @@ func TestBuildGatewayClass(t *testing.T) {
}
tests := []struct {
- gc *v1.GatewayClass
- np *NginxProxy
- crdMetadata map[types.NamespacedName]*metav1.PartialObjectMetadata
- expected *GatewayClass
- name string
- expNPInvalid bool
+ gc *v1.GatewayClass
+ nps map[types.NamespacedName]*NginxProxy
+ crdMetadata map[types.NamespacedName]*metav1.PartialObjectMetadata
+ expected *GatewayClass
+ name string
}{
{
gc: validGC,
@@ -191,46 +205,54 @@ func TestBuildGatewayClass(t *testing.T) {
},
{
gc: gcWithParams,
- np: &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- TypeMeta: metav1.TypeMeta{
- Kind: kinds.NginxProxy,
- },
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- ServiceName: helpers.GetPointer("my-svc"),
- },
- },
+ nps: map[types.NamespacedName]*NginxProxy{
+ npNsName: {
+ Source: np,
+ Valid: true,
},
- Valid: true,
},
expected: &GatewayClass{
Source: gcWithParams,
Valid: true,
Conditions: []conditions.Condition{staticConds.NewGatewayClassResolvedRefs()},
+ NginxProxy: &NginxProxy{
+ Valid: true,
+ Source: np,
+ },
},
name: "valid gatewayclass with paramsRef",
},
{
- gc: gcWithInvalidKind,
- np: &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- TypeMeta: metav1.TypeMeta{
- Kind: kinds.NginxProxy,
- },
+ gc: gcWithParamsNoNamespace,
+ expected: &GatewayClass{
+ Source: gcWithParamsNoNamespace,
+ Valid: true,
+ Conditions: []conditions.Condition{
+ staticConds.NewGatewayClassRefInvalid(
+ "spec.parametersRef.namespace: Required value: ParametersRef must specify Namespace",
+ ),
+ staticConds.NewGatewayClassInvalidParameters(
+ "spec.parametersRef.namespace: Required value: ParametersRef must specify Namespace",
+ ),
},
- Valid: true,
},
+ name: "valid gatewayclass with paramsRef missing namespace",
+ },
+ {
+ gc: gcWithInvalidKind,
expected: &GatewayClass{
Source: gcWithInvalidKind,
Valid: true,
Conditions: []conditions.Condition{
+ staticConds.NewGatewayClassRefInvalid(
+ "spec.parametersRef.kind: Unsupported value: \"Invalid\": supported values: \"NginxProxy\"",
+ ),
staticConds.NewGatewayClassInvalidParameters(
"spec.parametersRef.kind: Unsupported value: \"Invalid\": supported values: \"NginxProxy\"",
),
},
},
- name: "invalid gatewayclass with unsupported paramsRef Kind",
+ name: "valid gatewayclass with unsupported paramsRef Kind",
},
{
gc: gcWithParams,
@@ -244,38 +266,57 @@ func TestBuildGatewayClass(t *testing.T) {
),
},
},
- expNPInvalid: true,
- name: "invalid gatewayclass with paramsRef resource that doesn't exist",
+ name: "valid gatewayclass with paramsRef resource that doesn't exist",
},
{
gc: gcWithParams,
- np: &NginxProxy{
- Valid: false,
- ErrMsgs: field.ErrorList{
- field.Invalid(
- field.NewPath("spec", "telemetry", "serviceName"),
- "my-svc",
- "error",
- ),
- field.Invalid(
- field.NewPath("spec", "telemetry", "exporter", "endpoint"),
- "my-endpoint",
- "error",
- ),
+ nps: map[types.NamespacedName]*NginxProxy{
+ npNsName: {
+ Valid: false,
+ ErrMsgs: field.ErrorList{
+ field.Invalid(
+ field.NewPath("spec", "telemetry", "serviceName"),
+ "my-svc",
+ "error",
+ ),
+ field.Invalid(
+ field.NewPath("spec", "telemetry", "exporter", "endpoint"),
+ "my-endpoint",
+ "error",
+ ),
+ },
},
},
expected: &GatewayClass{
Source: gcWithParams,
Valid: true,
Conditions: []conditions.Condition{
+ staticConds.NewGatewayClassRefInvalid(
+ "[spec.telemetry.serviceName: Invalid value: \"my-svc\": error" +
+ ", spec.telemetry.exporter.endpoint: Invalid value: \"my-endpoint\": error]",
+ ),
staticConds.NewGatewayClassInvalidParameters(
"[spec.telemetry.serviceName: Invalid value: \"my-svc\": error" +
", spec.telemetry.exporter.endpoint: Invalid value: \"my-endpoint\": error]",
),
},
+ NginxProxy: &NginxProxy{
+ Valid: false,
+ ErrMsgs: field.ErrorList{
+ field.Invalid(
+ field.NewPath("spec", "telemetry", "serviceName"),
+ "my-svc",
+ "error",
+ ),
+ field.Invalid(
+ field.NewPath("spec", "telemetry", "exporter", "endpoint"),
+ "my-endpoint",
+ "error",
+ ),
+ },
+ },
},
- expNPInvalid: true,
- name: "invalid gatewayclass with invalid paramsRef resource",
+ name: "valid gatewayclass with invalid paramsRef resource",
},
{
gc: validGC,
@@ -294,11 +335,8 @@ func TestBuildGatewayClass(t *testing.T) {
t.Parallel()
g := NewWithT(t)
- result := buildGatewayClass(test.gc, test.np, test.crdMetadata)
+ result := buildGatewayClass(test.gc, test.nps, test.crdMetadata)
g.Expect(helpers.Diff(test.expected, result)).To(BeEmpty())
- if test.np != nil {
- g.Expect(test.np.Valid).ToNot(Equal(test.expNPInvalid))
- }
})
}
}
diff --git a/internal/mode/static/state/graph/graph.go b/internal/mode/static/state/graph/graph.go
index 0b56ec1018..6e1f6b78c0 100644
--- a/internal/mode/static/state/graph/graph.go
+++ b/internal/mode/static/state/graph/graph.go
@@ -14,7 +14,8 @@ import (
"sigs.k8s.io/gateway-api/apis/v1alpha3"
"sigs.k8s.io/gateway-api/apis/v1beta1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/controller/index"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds"
ngftypes "github.com/nginxinc/nginx-gateway-fabric/internal/framework/types"
@@ -35,10 +36,10 @@ type ClusterState struct {
CRDMetadata map[types.NamespacedName]*metav1.PartialObjectMetadata
BackendTLSPolicies map[types.NamespacedName]*v1alpha3.BackendTLSPolicy
ConfigMaps map[types.NamespacedName]*v1.ConfigMap
- NginxProxies map[types.NamespacedName]*ngfAPI.NginxProxy
+ NginxProxies map[types.NamespacedName]*ngfAPIv1alpha2.NginxProxy
GRPCRoutes map[types.NamespacedName]*gatewayv1.GRPCRoute
NGFPolicies map[PolicyKey]policies.Policy
- SnippetsFilters map[types.NamespacedName]*ngfAPI.SnippetsFilter
+ SnippetsFilters map[types.NamespacedName]*ngfAPIv1alpha1.SnippetsFilter
}
// Graph is a Graph-like representation of Gateway API resources.
@@ -70,10 +71,10 @@ type Graph struct {
ReferencedServices map[types.NamespacedName]*ReferencedService
// ReferencedCaCertConfigMaps includes ConfigMaps that have been referenced by any BackendTLSPolicies.
ReferencedCaCertConfigMaps map[types.NamespacedName]*CaCertConfigMap
+ // ReferencedNginxProxies includes NginxProxies that have been referenced by a GatewayClass or the winning Gateway.
+ ReferencedNginxProxies map[types.NamespacedName]*NginxProxy
// BackendTLSPolicies holds BackendTLSPolicy resources.
BackendTLSPolicies map[types.NamespacedName]*BackendTLSPolicy
- // NginxProxy holds the NginxProxy config for the GatewayClass.
- NginxProxy *NginxProxy
// NGFPolicies holds all NGF Policies.
NGFPolicies map[PolicyKey]*Policy
// GlobalSettings contains global settings from the current state of the graph that may be
@@ -126,9 +127,10 @@ func (g *Graph) IsReferenced(resourceType ngftypes.ObjectType, nsname types.Name
// Service Namespace should be the same Namespace as the EndpointSlice
_, exists := g.ReferencedServices[types.NamespacedName{Namespace: nsname.Namespace, Name: svcName}]
return exists
- // NginxProxy reference exists if it is linked to a GatewayClass.
- case *ngfAPI.NginxProxy:
- return isNginxProxyReferenced(nsname, g.GatewayClass)
+ // NginxProxy reference exists if the GatewayClass or winning Gateway references it.
+ case *ngfAPIv1alpha2.NginxProxy:
+ _, exists := g.ReferencedNginxProxies[nsname]
+ return exists
default:
return false
}
@@ -200,32 +202,39 @@ func BuildGraph(
validators validation.Validators,
protectedPorts ProtectedPorts,
) *Graph {
- var globalSettings *policies.GlobalSettings
-
processedGwClasses, gcExists := processGatewayClasses(state.GatewayClasses, gcName, controllerName)
if gcExists && processedGwClasses.Winner == nil {
// configured GatewayClass does not reference this controller
return &Graph{}
}
- npCfg := buildNginxProxy(state.NginxProxies, processedGwClasses.Winner, validators.GenericValidator)
- gc := buildGatewayClass(processedGwClasses.Winner, npCfg, state.CRDMetadata)
- if gc != nil && npCfg != nil && npCfg.Source != nil {
- spec := npCfg.Source.Spec
- globalSettings = &policies.GlobalSettings{
- NginxProxyValid: npCfg.Valid,
- TelemetryEnabled: spec.Telemetry != nil && spec.Telemetry.Exporter != nil,
- }
- }
+ processedGws := processGateways(state.Gateways, gcName)
+ processedNginxProxies := processNginxProxies(
+ state.NginxProxies,
+ validators.GenericValidator,
+ processedGwClasses.Winner,
+ processedGws.Winner,
+ )
+
+ gc := buildGatewayClass(
+ processedGwClasses.Winner,
+ processedNginxProxies,
+ state.CRDMetadata,
+ )
secretResolver := newSecretResolver(state.Secrets)
configMapResolver := newConfigMapResolver(state.ConfigMaps)
- processedGws := processGateways(state.Gateways, gcName)
-
refGrantResolver := newReferenceGrantResolver(state.ReferenceGrants)
- gw := buildGateway(processedGws.Winner, secretResolver, gc, refGrantResolver, protectedPorts)
+ gw := buildGateway(
+ processedGws.Winner,
+ secretResolver,
+ gc,
+ refGrantResolver,
+ protectedPorts,
+ processedNginxProxies,
+ )
processedBackendTLSPolicies := processBackendTLSPolicies(
state.BackendTLSPolicies,
@@ -235,13 +244,17 @@ func BuildGraph(
)
processedSnippetsFilters := processSnippetsFilters(state.SnippetsFilters)
+ var effectiveNginxProxy *EffectiveNginxProxy
+ if gw != nil {
+ effectiveNginxProxy = gw.EffectiveNginxProxy
+ }
routes := buildRoutesForGateways(
validators.HTTPFieldsValidator,
state.HTTPRoutes,
state.GRPCRoutes,
processedGws.GetAllNsNames(),
- npCfg,
+ effectiveNginxProxy,
processedSnippetsFilters,
)
@@ -249,17 +262,30 @@ func BuildGraph(
state.TLSRoutes,
processedGws.GetAllNsNames(),
state.Services,
- npCfg,
+ effectiveNginxProxy,
refGrantResolver,
)
bindRoutesToListeners(routes, l4routes, gw, state.Namespaces)
- addBackendRefsToRouteRules(routes, refGrantResolver, state.Services, processedBackendTLSPolicies, npCfg)
+ addBackendRefsToRouteRules(
+ routes,
+ refGrantResolver,
+ state.Services,
+ processedBackendTLSPolicies,
+ effectiveNginxProxy,
+ )
referencedNamespaces := buildReferencedNamespaces(state.Namespaces, gw)
referencedServices := buildReferencedServices(routes, l4routes, gw)
+ var globalSettings *policies.GlobalSettings
+ if gw != nil && gw.EffectiveNginxProxy != nil {
+ globalSettings = &policies.GlobalSettings{
+ NginxProxyValid: true, // for effective nginx proxy to be set, the config must be valid
+ TelemetryEnabled: telemetryEnabledForNginxProxy(gw.EffectiveNginxProxy),
+ }
+ }
// policies must be processed last because they rely on the state of the other resources in the graph
processedPolicies := processPolicies(
state.NGFPolicies,
@@ -283,8 +309,8 @@ func BuildGraph(
ReferencedNamespaces: referencedNamespaces,
ReferencedServices: referencedServices,
ReferencedCaCertConfigMaps: configMapResolver.getResolvedConfigMaps(),
+ ReferencedNginxProxies: processedNginxProxies,
BackendTLSPolicies: processedBackendTLSPolicies,
- NginxProxy: npCfg,
NGFPolicies: processedPolicies,
GlobalSettings: globalSettings,
SnippetsFilters: processedSnippetsFilters,
diff --git a/internal/mode/static/state/graph/graph_test.go b/internal/mode/static/state/graph/graph_test.go
index f2b71d05f8..0c5a1ef052 100644
--- a/internal/mode/static/state/graph/graph_test.go
+++ b/internal/mode/static/state/graph/graph_test.go
@@ -17,7 +17,8 @@ import (
"sigs.k8s.io/gateway-api/apis/v1alpha3"
"sigs.k8s.io/gateway-api/apis/v1beta1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/controller/index"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
@@ -110,35 +111,35 @@ func TestBuildGraph(t *testing.T) {
}
refSnippetsFilterExtensionRef := &gatewayv1.LocalObjectReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.SnippetsFilter,
Name: "ref-snippets-filter",
}
- unreferencedSnippetsFilter := &ngfAPI.SnippetsFilter{
+ unreferencedSnippetsFilter := &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "unref-snippets-filter",
Namespace: testNs,
},
- Spec: ngfAPI.SnippetsFilterSpec{
- Snippets: []ngfAPI.Snippet{
+ Spec: ngfAPIv1alpha1.SnippetsFilterSpec{
+ Snippets: []ngfAPIv1alpha1.Snippet{
{
- Context: ngfAPI.NginxContextMain,
+ Context: ngfAPIv1alpha1.NginxContextMain,
Value: "main snippet",
},
},
},
}
- referencedSnippetsFilter := &ngfAPI.SnippetsFilter{
+ referencedSnippetsFilter := &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "ref-snippets-filter",
Namespace: testNs,
},
- Spec: ngfAPI.SnippetsFilterSpec{
- Snippets: []ngfAPI.Snippet{
+ Spec: ngfAPIv1alpha1.SnippetsFilterSpec{
+ Snippets: []ngfAPIv1alpha1.Snippet{
{
- Context: ngfAPI.NginxContextHTTPServer,
+ Context: ngfAPIv1alpha1.NginxContextHTTPServer,
Value: "server snippet",
},
},
@@ -149,8 +150,8 @@ func TestBuildGraph(t *testing.T) {
Source: unreferencedSnippetsFilter,
Valid: true,
Referenced: false,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextMain: "main snippet",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextMain: "main snippet",
},
}
@@ -158,8 +159,8 @@ func TestBuildGraph(t *testing.T) {
Source: referencedSnippetsFilter,
Valid: true,
Referenced: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTPServer: "server snippet",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTPServer: "server snippet",
},
}
@@ -368,7 +369,7 @@ func TestBuildGraph(t *testing.T) {
},
}
- createGateway := func(name string) *gatewayv1.Gateway {
+ createGateway := func(name, nginxProxyName string) *gatewayv1.Gateway {
return &gatewayv1.Gateway{
ObjectMeta: metav1.ObjectMeta{
Namespace: testNs,
@@ -376,6 +377,13 @@ func TestBuildGraph(t *testing.T) {
},
Spec: gatewayv1.GatewaySpec{
GatewayClassName: gcName,
+ Infrastructure: &gatewayv1.GatewayInfrastructure{
+ ParametersRef: &gatewayv1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: nginxProxyName,
+ },
+ },
Listeners: []gatewayv1.Listener{
{
Name: "listener-80-1",
@@ -434,8 +442,35 @@ func TestBuildGraph(t *testing.T) {
}
}
- gw1 := createGateway("gateway-1")
- gw2 := createGateway("gateway-2")
+ gw1 := createGateway("gateway-1", "np-1")
+ gw2 := createGateway("gateway-2", "np-2")
+
+ // np1 is referenced by gw1 and sets the nginx error log to error.
+ // Since gw1 is the winning gateway, we expect this nginx proxy to be configured and merged with the gateway class
+ // nginx proxy configuration.
+ np1 := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "np-1",
+ Namespace: testNs,
+ },
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError),
+ },
+ },
+ }
+
+ // np2 is referenced by gw2 and sets the IPFamily to IPv6.
+ // Since gw2 is not the winning gateway, we do not expect this nginx proxy to be configured.
+ np2 := &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "np-2",
+ Namespace: testNs,
+ },
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ IPFamily: helpers.GetPointer(ngfAPIv1alpha2.IPv6),
+ },
+ }
svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{
@@ -526,20 +561,22 @@ func TestBuildGraph(t *testing.T) {
},
}
- proxy := &ngfAPI.NginxProxy{
+ // npGlobal is referenced by the gateway class, and we expect it to be configured and merged with np1.
+ npGlobal := &ngfAPIv1alpha2.NginxProxy{
ObjectMeta: metav1.ObjectMeta{
- Name: "nginx-proxy",
+ Name: "np-global",
+ Namespace: testNs,
},
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- Exporter: &ngfAPI.TelemetryExporter{
- Endpoint: "1.2.3.4:123",
- Interval: helpers.GetPointer(ngfAPI.Duration("5s")),
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("1.2.3.4:123"),
+ Interval: helpers.GetPointer(ngfAPIv1alpha1.Duration("5s")),
BatchSize: helpers.GetPointer(int32(512)),
BatchCount: helpers.GetPointer(int32(4)),
},
ServiceName: helpers.GetPointer("my-svc"),
- SpanAttributes: []ngfAPI.SpanAttribute{
+ SpanAttributes: []ngfAPIv1alpha1.SpanAttribute{
{Key: "key", Value: "value"},
},
},
@@ -553,13 +590,13 @@ func TestBuildGraph(t *testing.T) {
// Testing one type of policy per attachment point should suffice.
polGVK := schema.GroupVersionKind{Kind: kinds.ClientSettingsPolicy}
hrPolicyKey := PolicyKey{GVK: polGVK, NsName: types.NamespacedName{Namespace: testNs, Name: "hrPolicy"}}
- hrPolicy := &ngfAPI.ClientSettingsPolicy{
+ hrPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "hrPolicy",
Namespace: testNs,
},
TypeMeta: metav1.TypeMeta{Kind: kinds.ClientSettingsPolicy},
- Spec: ngfAPI.ClientSettingsPolicySpec{
+ Spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
TargetRef: createTestRef(kinds.HTTPRoute, gatewayv1.GroupName, "hr-1"),
},
}
@@ -586,13 +623,13 @@ func TestBuildGraph(t *testing.T) {
}
gwPolicyKey := PolicyKey{GVK: polGVK, NsName: types.NamespacedName{Namespace: testNs, Name: "gwPolicy"}}
- gwPolicy := &ngfAPI.ClientSettingsPolicy{
+ gwPolicy := &ngfAPIv1alpha1.ClientSettingsPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "gwPolicy",
Namespace: testNs,
},
TypeMeta: metav1.TypeMeta{Kind: kinds.ClientSettingsPolicy},
- Spec: ngfAPI.ClientSettingsPolicySpec{
+ Spec: ngfAPIv1alpha1.ClientSettingsPolicySpec{
TargetRef: createTestRef(kinds.Gateway, gatewayv1.GroupName, "gateway-1"),
},
}
@@ -661,14 +698,16 @@ func TestBuildGraph(t *testing.T) {
ConfigMaps: map[types.NamespacedName]*v1.ConfigMap{
client.ObjectKeyFromObject(cm): cm,
},
- NginxProxies: map[types.NamespacedName]*ngfAPI.NginxProxy{
- client.ObjectKeyFromObject(proxy): proxy,
+ NginxProxies: map[types.NamespacedName]*ngfAPIv1alpha2.NginxProxy{
+ client.ObjectKeyFromObject(npGlobal): npGlobal,
+ client.ObjectKeyFromObject(np1): np1,
+ client.ObjectKeyFromObject(np2): np2,
},
NGFPolicies: map[PolicyKey]policies.Policy{
hrPolicyKey: hrPolicy,
gwPolicyKey: gwPolicy,
},
- SnippetsFilters: map[types.NamespacedName]*ngfAPI.SnippetsFilter{
+ SnippetsFilters: map[types.NamespacedName]*ngfAPIv1alpha1.SnippetsFilter{
client.ObjectKeyFromObject(unreferencedSnippetsFilter): unreferencedSnippetsFilter,
client.ObjectKeyFromObject(referencedSnippetsFilter): referencedSnippetsFilter,
},
@@ -820,6 +859,10 @@ func TestBuildGraph(t *testing.T) {
Source: gc,
Valid: true,
Conditions: []conditions.Condition{staticConds.NewGatewayClassResolvedRefs()},
+ NginxProxy: &NginxProxy{
+ Source: npGlobal,
+ Valid: true,
+ },
},
Gateway: &Gateway{
Source: gw1,
@@ -872,6 +915,28 @@ func TestBuildGraph(t *testing.T) {
},
Valid: true,
Policies: []*Policy{processedGwPolicy},
+ NginxProxy: &NginxProxy{
+ Source: np1,
+ Valid: true,
+ },
+ EffectiveNginxProxy: &EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("1.2.3.4:123"),
+ Interval: helpers.GetPointer(ngfAPIv1alpha1.Duration("5s")),
+ BatchSize: helpers.GetPointer(int32(512)),
+ BatchCount: helpers.GetPointer(int32(4)),
+ },
+ ServiceName: helpers.GetPointer("my-svc"),
+ SpanAttributes: []ngfAPIv1alpha1.SpanAttribute{
+ {Key: "key", Value: "value"},
+ },
+ },
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError),
+ },
+ },
+ Conditions: []conditions.Condition{staticConds.NewGatewayResolvedRefs()},
},
IgnoredGateways: map[types.NamespacedName]*gatewayv1.Gateway{
{Namespace: testNs, Name: "gateway-2"}: gw2,
@@ -906,9 +971,15 @@ func TestBuildGraph(t *testing.T) {
BackendTLSPolicies: map[types.NamespacedName]*BackendTLSPolicy{
client.ObjectKeyFromObject(btp.Source): &btp,
},
- NginxProxy: &NginxProxy{
- Source: proxy,
- Valid: true,
+ ReferencedNginxProxies: map[types.NamespacedName]*NginxProxy{
+ client.ObjectKeyFromObject(npGlobal): {
+ Source: npGlobal,
+ Valid: true,
+ },
+ client.ObjectKeyFromObject(np1): {
+ Source: np1,
+ Valid: true,
+ },
},
NGFPolicies: map[PolicyKey]*Policy{
hrPolicyKey: processedRoutePolicy,
@@ -941,9 +1012,10 @@ func TestBuildGraph(t *testing.T) {
Spec: gatewayv1.GatewayClassSpec{
ControllerName: controllerName,
ParametersRef: &gatewayv1.ParametersReference{
- Group: gatewayv1.Group("gateway.nginx.org"),
- Kind: gatewayv1.Kind(kinds.NginxProxy),
- Name: "nginx-proxy",
+ Group: gatewayv1.Group("gateway.nginx.org"),
+ Kind: gatewayv1.Kind(kinds.NginxProxy),
+ Name: "np-global",
+ Namespace: helpers.GetPointer(gatewayv1.Namespace(testNs)),
},
},
}
@@ -1122,27 +1194,15 @@ func TestIsReferenced(t *testing.T) {
},
}
- gcWithNginxProxy := &GatewayClass{
- Source: &gatewayv1.GatewayClass{
- Spec: gatewayv1.GatewayClassSpec{
- ParametersRef: &gatewayv1.ParametersReference{
- Group: ngfAPI.GroupName,
- Kind: gatewayv1.Kind(kinds.NginxProxy),
- Name: "nginx-proxy-in-gc",
- },
- },
- },
- }
-
- npNotInGatewayClass := &ngfAPI.NginxProxy{
+ npNotReferenced := &ngfAPIv1alpha2.NginxProxy{
ObjectMeta: metav1.ObjectMeta{
- Name: "nginx-proxy",
+ Name: "nginx-proxy-not-ref",
},
}
- npInGatewayClass := &ngfAPI.NginxProxy{
+ npReferenced := &ngfAPIv1alpha2.NginxProxy{
ObjectMeta: metav1.ObjectMeta{
- Name: "nginx-proxy-in-gc",
+ Name: "nginx-proxy-ref",
},
}
@@ -1165,6 +1225,11 @@ func TestIsReferenced(t *testing.T) {
CACert: []byte(caBlock),
},
},
+ ReferencedNginxProxies: map[types.NamespacedName]*NginxProxy{
+ client.ObjectKeyFromObject(npReferenced): {
+ Source: npReferenced,
+ },
+ },
}
tests := []struct {
@@ -1295,16 +1360,14 @@ func TestIsReferenced(t *testing.T) {
// NginxProxy tests
{
- name: "NginxProxy is referenced in GatewayClass",
- resource: npInGatewayClass,
- gc: gcWithNginxProxy,
+ name: "NginxProxy is referenced",
+ resource: npReferenced,
graph: graph,
expected: true,
},
{
- name: "NginxProxy is not referenced in GatewayClass",
- resource: npNotInGatewayClass,
- gc: gcWithNginxProxy,
+ name: "NginxProxy is not referenced",
+ resource: npNotReferenced,
graph: graph,
expected: false,
},
diff --git a/internal/mode/static/state/graph/grpcroute_test.go b/internal/mode/static/state/graph/grpcroute_test.go
index 793458f837..19b14e4cc0 100644
--- a/internal/mode/static/state/graph/grpcroute_test.go
+++ b/internal/mode/static/state/graph/grpcroute_test.go
@@ -10,7 +10,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
v1 "sigs.k8s.io/gateway-api/apis/v1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds"
@@ -88,7 +88,7 @@ func TestBuildGRPCRoutes(t *testing.T) {
ExtensionRef: &v1.LocalObjectReference{
Name: "sf",
Kind: kinds.SnippetsFilter,
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
},
}
@@ -110,15 +110,15 @@ func TestBuildGRPCRoutes(t *testing.T) {
client.ObjectKeyFromObject(grWrongGateway): grWrongGateway,
}
- sf := &ngfAPI.SnippetsFilter{
+ sf := &ngfAPIv1alpha1.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "sf",
},
- Spec: ngfAPI.SnippetsFilterSpec{
- Snippets: []ngfAPI.Snippet{
+ Spec: ngfAPIv1alpha1.SnippetsFilterSpec{
+ Snippets: []ngfAPIv1alpha1.Snippet{
{
- Context: ngfAPI.NginxContextHTTP,
+ Context: ngfAPIv1alpha1.NginxContextHTTP,
Value: "http snippet",
},
},
@@ -158,8 +158,8 @@ func TestBuildGRPCRoutes(t *testing.T) {
ResolvedExtensionRef: &ExtensionRefFilter{
SnippetsFilter: &SnippetsFilter{
Source: sf,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTP: "http snippet",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTP: "http snippet",
},
Valid: true,
Referenced: true,
@@ -194,12 +194,8 @@ func TestBuildGRPCRoutes(t *testing.T) {
validator := &validationfakes.FakeHTTPFieldsValidator{}
- npCfg := &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- DisableHTTP2: false,
- },
- },
+ npCfg := &EffectiveNginxProxy{
+ DisableHTTP2: helpers.GetPointer(false),
}
for _, test := range tests {
@@ -211,8 +207,8 @@ func TestBuildGRPCRoutes(t *testing.T) {
client.ObjectKeyFromObject(sf): {
Source: sf,
Valid: true,
- Snippets: map[ngfAPI.NginxContext]string{
- ngfAPI.NginxContextHTTP: "http snippet",
+ Snippets: map[ngfAPIv1alpha1.NginxContext]string{
+ ngfAPIv1alpha1.NginxContextHTTP: "http snippet",
},
},
}
@@ -351,7 +347,7 @@ func TestBuildGRPCRoute(t *testing.T) {
grValidFilterRule := createGRPCMethodMatch("myService", "myMethod", "Exact")
validSnippetsFilterRef := &v1.LocalObjectReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.SnippetsFilter,
Name: "sf",
}
@@ -409,7 +405,7 @@ func TestBuildGRPCRoute(t *testing.T) {
{
Type: v1.GRPCRouteFilterExtensionRef,
ExtensionRef: &v1.LocalObjectReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.SnippetsFilter,
Name: "does-not-exist",
},
@@ -428,7 +424,7 @@ func TestBuildGRPCRoute(t *testing.T) {
{
Type: v1.GRPCRouteFilterExtensionRef,
ExtensionRef: &v1.LocalObjectReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha1.GroupName,
Kind: kinds.SnippetsFilter,
Name: "does-not-exist",
},
diff --git a/internal/mode/static/state/graph/nginxproxy.go b/internal/mode/static/state/graph/nginxproxy.go
index fa55f209c0..c2b65e4e9a 100644
--- a/internal/mode/static/state/graph/nginxproxy.go
+++ b/internal/mode/static/state/graph/nginxproxy.go
@@ -1,15 +1,18 @@
package graph
import (
+ "encoding/json"
+ "fmt"
"slices"
"k8s.io/apimachinery/pkg/types"
k8svalidation "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
+ "sigs.k8s.io/controller-runtime/pkg/client"
v1 "sigs.k8s.io/gateway-api/apis/v1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
- "github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/validation"
)
@@ -17,45 +20,169 @@ import (
// NginxProxy represents the NginxProxy resource.
type NginxProxy struct {
// Source is the source resource.
- Source *ngfAPI.NginxProxy
+ Source *ngfAPIv1alpha2.NginxProxy
// ErrMsgs contains the validation errors if they exist, to be included in the GatewayClass condition.
ErrMsgs field.ErrorList
// Valid shows whether the NginxProxy is valid.
Valid bool
}
-// buildNginxProxy validates and returns the NginxProxy associated with the GatewayClass (if it exists).
-func buildNginxProxy(
- nps map[types.NamespacedName]*ngfAPI.NginxProxy,
- gc *v1.GatewayClass,
+// EffectiveNginxProxy holds the result of merging the NginxProxySpec on this resource with the NginxProxySpec on the
+// GatewayClass resource. This is the effective set of config that should be applied to the Gateway.
+type EffectiveNginxProxy ngfAPIv1alpha2.NginxProxySpec
+
+// buildEffectiveNginxProxy builds the effective NginxProxy for the Gateway by merging the GatewayClass and Gateway
+// NginxProxy resources. Fields specified on the Gateway NginxProxy override those set on the GatewayClass NginxProxy.
+func buildEffectiveNginxProxy(gatewayClassNp, gatewayNp *NginxProxy) *EffectiveNginxProxy {
+ gcNpValid, gwNpValid := nginxProxyValid(gatewayClassNp), nginxProxyValid(gatewayNp)
+ if !gcNpValid && !gwNpValid {
+ return nil
+ }
+
+ if !gcNpValid {
+ enp := EffectiveNginxProxy(*gatewayNp.Source.Spec.DeepCopy())
+ return &enp
+ }
+
+ if !gwNpValid {
+ enp := EffectiveNginxProxy(*gatewayClassNp.Source.Spec.DeepCopy())
+ return &enp
+ }
+
+ global := EffectiveNginxProxy(*gatewayClassNp.Source.Spec.DeepCopy())
+ local := EffectiveNginxProxy(*gatewayNp.Source.Spec.DeepCopy())
+
+ // by marshaling the local config and then unmarshaling on top of the global config,
+ // we ensure that any unset local values are set with the global values
+ localBytes, err := json.Marshal(local)
+ if err != nil {
+ panic(
+ fmt.Sprintf(
+ "could not marshal NginxProxy resource referenced by Gateway %s",
+ client.ObjectKeyFromObject(gatewayNp.Source),
+ ),
+ )
+ }
+
+ err = json.Unmarshal(localBytes, &global)
+ if err != nil {
+ panic(
+ fmt.Sprintf(
+ "could not unmarshal NginxProxy resource referenced by GatewayClass %s",
+ client.ObjectKeyFromObject(gatewayClassNp.Source),
+ ),
+ )
+ }
+
+ // this json trick doesn't work for unsetting slices, so we need to do that manually.
+ if local.Telemetry != nil {
+ if local.Telemetry.DisabledFeatures != nil && len(local.Telemetry.DisabledFeatures) == 0 {
+ global.Telemetry.DisabledFeatures = []ngfAPIv1alpha2.DisableTelemetryFeature{}
+ }
+
+ if local.Telemetry.SpanAttributes != nil && len(local.Telemetry.SpanAttributes) == 0 {
+ global.Telemetry.SpanAttributes = []ngfAPIv1alpha1.SpanAttribute{}
+ }
+ }
+
+ if local.RewriteClientIP != nil {
+ if local.RewriteClientIP.TrustedAddresses != nil && len(local.RewriteClientIP.TrustedAddresses) == 0 {
+ global.RewriteClientIP.TrustedAddresses = []ngfAPIv1alpha2.Address{}
+ }
+ }
+
+ return &global
+}
+
+func nginxProxyValid(np *NginxProxy) bool {
+ return np != nil && np.Source != nil && np.Valid
+}
+
+func telemetryEnabledForNginxProxy(np *EffectiveNginxProxy) bool {
+ if np.Telemetry == nil || np.Telemetry.Exporter == nil || np.Telemetry.Exporter.Endpoint == nil {
+ return false
+ }
+
+ if slices.Contains(np.Telemetry.DisabledFeatures, ngfAPIv1alpha2.DisableTracing) {
+ return false
+ }
+
+ return true
+}
+
+func processNginxProxies(
+ nps map[types.NamespacedName]*ngfAPIv1alpha2.NginxProxy,
validator validation.GenericValidator,
-) *NginxProxy {
+ gc *v1.GatewayClass,
+ winningGateway *v1.Gateway,
+) map[types.NamespacedName]*NginxProxy {
+ referencedNginxProxies := make(map[types.NamespacedName]*NginxProxy)
+
if gcReferencesAnyNginxProxy(gc) {
- npCfg := nps[types.NamespacedName{Name: gc.Spec.ParametersRef.Name}]
- if npCfg != nil {
- errs := validateNginxProxy(validator, npCfg)
-
- return &NginxProxy{
- Source: npCfg,
- Valid: len(errs) == 0,
- ErrMsgs: errs,
+ // we will ignore references without namespaces
+ // the gateway class status will contain an error message about the missing namespace
+ if gc.Spec.ParametersRef.Namespace != nil {
+ refNp := types.NamespacedName{
+ Name: gc.Spec.ParametersRef.Name,
+ Namespace: string(*gc.Spec.ParametersRef.Namespace),
+ }
+
+ if np, ok := nps[refNp]; ok {
+ referencedNginxProxies[refNp] = buildNginxProxy(np, validator)
}
}
}
- return nil
+ if gwReferencesAnyNginxProxy(winningGateway) {
+ refNp := types.NamespacedName{
+ Name: winningGateway.Spec.Infrastructure.ParametersRef.Name,
+ Namespace: winningGateway.Namespace,
+ }
+
+ if np, ok := nps[refNp]; ok {
+ referencedNginxProxies[refNp] = buildNginxProxy(np, validator)
+ }
+ }
+
+ if len(referencedNginxProxies) == 0 {
+ return nil
+ }
+
+ return referencedNginxProxies
}
-// isNginxProxyReferenced returns whether or not a specific NginxProxy is referenced in the GatewayClass.
-func isNginxProxyReferenced(npNSName types.NamespacedName, gc *GatewayClass) bool {
- return gc != nil && gcReferencesAnyNginxProxy(gc.Source) && gc.Source.Spec.ParametersRef.Name == npNSName.Name
+// buildNginxProxy validates and returns the NginxProxy associated with the GatewayClass (if it exists).
+func buildNginxProxy(
+ np *ngfAPIv1alpha2.NginxProxy,
+ validator validation.GenericValidator,
+) *NginxProxy {
+ if np != nil {
+ errs := validateNginxProxy(validator, np)
+
+ return &NginxProxy{
+ Source: np,
+ Valid: len(errs) == 0,
+ ErrMsgs: errs,
+ }
+ }
+
+ return nil
}
// gcReferencesNginxProxy returns whether a GatewayClass references any NginxProxy resource.
func gcReferencesAnyNginxProxy(gc *v1.GatewayClass) bool {
if gc != nil {
ref := gc.Spec.ParametersRef
- return ref != nil && ref.Group == ngfAPI.GroupName && ref.Kind == v1.Kind(kinds.NginxProxy)
+ return ref != nil && ref.Group == ngfAPIv1alpha2.GroupName && ref.Kind == kinds.NginxProxy
+ }
+
+ return false
+}
+
+func gwReferencesAnyNginxProxy(gw *v1.Gateway) bool {
+ if gw != nil && gw.Spec.Infrastructure != nil {
+ ref := gw.Spec.Infrastructure.ParametersRef
+ return ref != nil && ref.Group == ngfAPIv1alpha2.GroupName && ref.Kind == kinds.NginxProxy
}
return false
@@ -64,7 +191,7 @@ func gcReferencesAnyNginxProxy(gc *v1.GatewayClass) bool {
// validateNginxProxy performs re-validation on string values in the case of CRD validation failure.
func validateNginxProxy(
validator validation.GenericValidator,
- npCfg *ngfAPI.NginxProxy,
+ npCfg *ngfAPIv1alpha2.NginxProxy,
) field.ErrorList {
var allErrs field.ErrorList
spec := field.NewPath("spec")
@@ -85,8 +212,8 @@ func validateNginxProxy(
exp := telemetry.Exporter
expPath := telPath.Child("exporter")
- if exp.Endpoint != "" {
- if err := validator.ValidateEndpoint(exp.Endpoint); err != nil {
+ if exp.Endpoint != nil {
+ if err := validator.ValidateEndpoint(*exp.Endpoint); err != nil {
allErrs = append(allErrs, field.Invalid(expPath.Child("endpoint"), exp.Endpoint, err.Error()))
}
}
@@ -116,17 +243,15 @@ func validateNginxProxy(
ipFamily := npCfg.Spec.IPFamily
ipFamilyPath := spec.Child("ipFamily")
switch *ipFamily {
- case ngfAPI.Dual, ngfAPI.IPv4, ngfAPI.IPv6:
+ case ngfAPIv1alpha2.Dual, ngfAPIv1alpha2.IPv4, ngfAPIv1alpha2.IPv6:
default:
allErrs = append(
allErrs,
field.NotSupported(
ipFamilyPath,
ipFamily,
- []string{string(ngfAPI.Dual), string(ngfAPI.IPv4), string(ngfAPI.IPv6)}))
+ []string{string(ngfAPIv1alpha2.Dual), string(ngfAPIv1alpha2.IPv4), string(ngfAPIv1alpha2.IPv6)}))
}
- } else {
- npCfg.Spec.IPFamily = helpers.GetPointer[ngfAPI.IPFamilyType](ngfAPI.Dual)
}
allErrs = append(allErrs, validateLogging(npCfg)...)
@@ -136,7 +261,7 @@ func validateNginxProxy(
return allErrs
}
-func validateLogging(npCfg *ngfAPI.NginxProxy) field.ErrorList {
+func validateLogging(npCfg *ngfAPIv1alpha2.NginxProxy) field.ErrorList {
var allErrs field.ErrorList
spec := field.NewPath("spec")
@@ -148,14 +273,14 @@ func validateLogging(npCfg *ngfAPI.NginxProxy) field.ErrorList {
errLevel := string(*logging.ErrorLevel)
validLogLevels := []string{
- string(ngfAPI.NginxLogLevelDebug),
- string(ngfAPI.NginxLogLevelInfo),
- string(ngfAPI.NginxLogLevelNotice),
- string(ngfAPI.NginxLogLevelWarn),
- string(ngfAPI.NginxLogLevelError),
- string(ngfAPI.NginxLogLevelCrit),
- string(ngfAPI.NginxLogLevelAlert),
- string(ngfAPI.NginxLogLevelEmerg),
+ string(ngfAPIv1alpha2.NginxLogLevelDebug),
+ string(ngfAPIv1alpha2.NginxLogLevelInfo),
+ string(ngfAPIv1alpha2.NginxLogLevelNotice),
+ string(ngfAPIv1alpha2.NginxLogLevelWarn),
+ string(ngfAPIv1alpha2.NginxLogLevelError),
+ string(ngfAPIv1alpha2.NginxLogLevelCrit),
+ string(ngfAPIv1alpha2.NginxLogLevelAlert),
+ string(ngfAPIv1alpha2.NginxLogLevelEmerg),
}
if !slices.Contains(validLogLevels, errLevel) {
@@ -173,7 +298,7 @@ func validateLogging(npCfg *ngfAPI.NginxProxy) field.ErrorList {
return allErrs
}
-func validateRewriteClientIP(npCfg *ngfAPI.NginxProxy) field.ErrorList {
+func validateRewriteClientIP(npCfg *ngfAPIv1alpha2.NginxProxy) field.ErrorList {
var allErrs field.ErrorList
spec := field.NewPath("spec")
@@ -192,14 +317,17 @@ func validateRewriteClientIP(npCfg *ngfAPI.NginxProxy) field.ErrorList {
}
switch mode {
- case ngfAPI.RewriteClientIPModeProxyProtocol, ngfAPI.RewriteClientIPModeXForwardedFor:
+ case ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol, ngfAPIv1alpha2.RewriteClientIPModeXForwardedFor:
default:
allErrs = append(
allErrs,
field.NotSupported(
rewriteClientIPPath.Child("mode"),
mode,
- []string{string(ngfAPI.RewriteClientIPModeProxyProtocol), string(ngfAPI.RewriteClientIPModeXForwardedFor)},
+ []string{
+ string(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
+ string(ngfAPIv1alpha2.RewriteClientIPModeXForwardedFor),
+ },
),
)
}
@@ -216,15 +344,15 @@ func validateRewriteClientIP(npCfg *ngfAPI.NginxProxy) field.ErrorList {
valuePath := trustedAddressesPath.Child("value")
switch addr.Type {
- case ngfAPI.CIDRAddressType:
+ case ngfAPIv1alpha2.CIDRAddressType:
if err := k8svalidation.IsValidCIDR(valuePath, addr.Value); err != nil {
allErrs = append(allErrs, err...)
}
- case ngfAPI.IPAddressType:
+ case ngfAPIv1alpha2.IPAddressType:
if err := k8svalidation.IsValidIP(valuePath, addr.Value); err != nil {
allErrs = append(allErrs, err...)
}
- case ngfAPI.HostnameAddressType:
+ case ngfAPIv1alpha2.HostnameAddressType:
if errs := k8svalidation.IsDNS1123Subdomain(addr.Value); len(errs) > 0 {
for _, e := range errs {
allErrs = append(allErrs, field.Invalid(valuePath, addr.Value, e))
@@ -236,9 +364,9 @@ func validateRewriteClientIP(npCfg *ngfAPI.NginxProxy) field.ErrorList {
field.NotSupported(trustedAddressesPath.Child("type"),
addr.Type,
[]string{
- string(ngfAPI.CIDRAddressType),
- string(ngfAPI.IPAddressType),
- string(ngfAPI.HostnameAddressType),
+ string(ngfAPIv1alpha2.CIDRAddressType),
+ string(ngfAPIv1alpha2.IPAddressType),
+ string(ngfAPIv1alpha2.HostnameAddressType),
},
),
)
diff --git a/internal/mode/static/state/graph/nginxproxy_test.go b/internal/mode/static/state/graph/nginxproxy_test.go
index 54447f3b31..e2cf12d952 100644
--- a/internal/mode/static/state/graph/nginxproxy_test.go
+++ b/internal/mode/static/state/graph/nginxproxy_test.go
@@ -7,78 +7,281 @@ import (
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/util/validation/field"
v1 "sigs.k8s.io/gateway-api/apis/v1"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha1 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPIv1alpha2 "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/kinds"
+ "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/validation"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/validation/validationfakes"
)
-func TestGetNginxProxy(t *testing.T) {
+func createValidValidator() *validationfakes.FakeGenericValidator {
+ v := &validationfakes.FakeGenericValidator{}
+ v.ValidateEscapedStringNoVarExpansionReturns(nil)
+ v.ValidateEndpointReturns(nil)
+ v.ValidateServiceNameReturns(nil)
+ v.ValidateNginxDurationReturns(nil)
+
+ return v
+}
+
+func createInvalidValidator() *validationfakes.FakeGenericValidator {
+ v := &validationfakes.FakeGenericValidator{}
+ v.ValidateEscapedStringNoVarExpansionReturns(errors.New("error"))
+ v.ValidateEndpointReturns(errors.New("error"))
+ v.ValidateServiceNameReturns(errors.New("error"))
+ v.ValidateNginxDurationReturns(errors.New("error"))
+
+ return v
+}
+
+func TestBuildEffectiveNginxProxy(t *testing.T) {
t.Parallel()
+
+ newTestNginxProxy := func(
+ ipFam ngfAPIv1alpha2.IPFamilyType,
+ disableFeats []ngfAPIv1alpha2.DisableTelemetryFeature,
+ interval ngfAPIv1alpha1.Duration,
+ batchSize int32,
+ batchCount int32,
+ endpoint string,
+ serviceName string,
+ spanAttr ngfAPIv1alpha1.SpanAttribute,
+ mode ngfAPIv1alpha2.RewriteClientIPModeType,
+ trustedAddr []ngfAPIv1alpha2.Address,
+ logLevel ngfAPIv1alpha2.NginxErrorLogLevel,
+ setIP bool,
+ disableHTTP bool,
+ ) *ngfAPIv1alpha2.NginxProxy {
+ return &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ IPFamily: &ipFam,
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ DisabledFeatures: disableFeats,
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Interval: &interval,
+ BatchSize: &batchSize,
+ BatchCount: &batchCount,
+ Endpoint: &endpoint,
+ },
+ ServiceName: &serviceName,
+ SpanAttributes: []ngfAPIv1alpha1.SpanAttribute{spanAttr},
+ },
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: &mode,
+ SetIPRecursively: &setIP,
+ TrustedAddresses: trustedAddr,
+ },
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: &logLevel,
+ },
+ DisableHTTP2: &disableHTTP,
+ },
+ }
+ }
+
+ getNginxProxy := func() *ngfAPIv1alpha2.NginxProxy {
+ return newTestNginxProxy(
+ ngfAPIv1alpha2.Dual,
+ []ngfAPIv1alpha2.DisableTelemetryFeature{ngfAPIv1alpha2.DisableTracing},
+ "10s",
+ 10,
+ 5,
+ "endpoint:1234",
+ "my-service",
+ ngfAPIv1alpha1.SpanAttribute{Key: "key", Value: "val"},
+ ngfAPIv1alpha2.RewriteClientIPModeXForwardedFor,
+ []ngfAPIv1alpha2.Address{{Type: ngfAPIv1alpha2.IPAddressType, Value: "10.0.0.1"}},
+ ngfAPIv1alpha2.NginxLogLevelAlert,
+ true,
+ false,
+ )
+ }
+
+ getNginxProxyAllFieldsSetDifferently := func() *ngfAPIv1alpha2.NginxProxy {
+ return newTestNginxProxy(
+ ngfAPIv1alpha2.IPv6,
+ []ngfAPIv1alpha2.DisableTelemetryFeature{},
+ "5s",
+ 8,
+ 2,
+ "diff-endpoint:1234",
+ "diff-service",
+ ngfAPIv1alpha1.SpanAttribute{Key: "diff-key", Value: "diff-val"},
+ ngfAPIv1alpha2.RewriteClientIPModeXForwardedFor,
+ []ngfAPIv1alpha2.Address{{Type: ngfAPIv1alpha2.CIDRAddressType, Value: "10.0.0.1/24"}},
+ ngfAPIv1alpha2.NginxLogLevelError,
+ false,
+ true,
+ )
+ }
+
+ getExpSpec := func() *EffectiveNginxProxy {
+ enp := EffectiveNginxProxy(getNginxProxy().Spec)
+ return &enp
+ }
+
+ getModifiedExpSpec := func(mod func(*ngfAPIv1alpha2.NginxProxy) *ngfAPIv1alpha2.NginxProxy) *EffectiveNginxProxy {
+ enp := EffectiveNginxProxy(mod(getNginxProxy()).Spec)
+ return &enp
+ }
+
tests := []struct {
- nps map[types.NamespacedName]*ngfAPI.NginxProxy
- gc *v1.GatewayClass
- expNP *NginxProxy
- name string
+ gcNp *NginxProxy
+ gwNp *NginxProxy
+ exp *EffectiveNginxProxy
+ name string
}{
{
- nps: map[types.NamespacedName]*ngfAPI.NginxProxy{
- {Name: "np1"}: {},
- },
- gc: nil,
- expNP: nil,
- name: "nil gatewayclass",
+ name: "both gateway class and gateway nginx proxies are nil",
+ gcNp: nil,
+ gwNp: nil,
+ exp: nil,
},
{
- nps: map[types.NamespacedName]*ngfAPI.NginxProxy{},
- gc: &v1.GatewayClass{
- Spec: v1.GatewayClassSpec{
- ParametersRef: &v1.ParametersReference{
- Group: ngfAPI.GroupName,
- Kind: v1.Kind(kinds.NginxProxy),
- Name: "np1",
+ name: "nil gateway class nginx proxy",
+ gcNp: nil,
+ gwNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ exp: getExpSpec(),
+ },
+ {
+ name: "nil gateway class nginx proxy; invalid gateway nginx proxy",
+ gcNp: nil,
+ gwNp: &NginxProxy{Valid: false, Source: getNginxProxy()},
+ exp: nil,
+ },
+ {
+ name: "nil gateway class nginx proxy; nil gateway nginx proxy source",
+ gcNp: nil,
+ gwNp: &NginxProxy{Valid: true, Source: nil},
+ exp: nil,
+ },
+ {
+ name: "invalid gateway class nginx proxy",
+ gcNp: &NginxProxy{Valid: false},
+ gwNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ exp: getExpSpec(),
+ },
+ {
+ name: "nil gateway class nginx proxy source",
+ gcNp: &NginxProxy{Valid: true, Source: nil},
+ gwNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ exp: getExpSpec(),
+ },
+ {
+ name: "nil gateway nginx proxy",
+ gcNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ gwNp: nil,
+ exp: getExpSpec(),
+ },
+ {
+ name: "invalid gateway nginx proxy",
+ gcNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ gwNp: &NginxProxy{Valid: false},
+ exp: getExpSpec(),
+ },
+ {
+ name: "nil gateway nginx proxy source",
+ gcNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ gwNp: &NginxProxy{Valid: true, Source: nil},
+ exp: getExpSpec(),
+ },
+ {
+ name: "both have all fields set; gateway values should win",
+ gcNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ gwNp: &NginxProxy{Valid: true, Source: getNginxProxyAllFieldsSetDifferently()},
+ exp: getModifiedExpSpec(func(_ *ngfAPIv1alpha2.NginxProxy) *ngfAPIv1alpha2.NginxProxy {
+ return getNginxProxyAllFieldsSetDifferently()
+ }),
+ },
+ {
+ name: "gateway nginx proxy overrides nginx error log level",
+ gcNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ gwNp: &NginxProxy{
+ Valid: true,
+ Source: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelDebug),
+ },
},
},
},
- expNP: nil,
- name: "no nginxproxy resources",
+ exp: getModifiedExpSpec(func(np *ngfAPIv1alpha2.NginxProxy) *ngfAPIv1alpha2.NginxProxy {
+ np.Spec.Logging.ErrorLevel = helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelDebug)
+ return np
+ }),
},
{
- nps: map[types.NamespacedName]*ngfAPI.NginxProxy{
- {Name: "np1"}: {
- ObjectMeta: metav1.ObjectMeta{
- Name: "np1",
- },
- },
- {Name: "np2"}: {
- ObjectMeta: metav1.ObjectMeta{
- Name: "np2",
+ name: "gateway nginx proxy overrides select telemetry values",
+ gcNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ gwNp: &NginxProxy{
+ Valid: true,
+ Source: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ ServiceName: helpers.GetPointer("new-service-name"),
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ BatchSize: helpers.GetPointer[int32](20),
+ Endpoint: helpers.GetPointer("new-endpoint"),
+ },
+ },
},
},
},
- gc: &v1.GatewayClass{
- Spec: v1.GatewayClassSpec{
- ParametersRef: &v1.ParametersReference{
- Group: ngfAPI.GroupName,
- Kind: v1.Kind(kinds.NginxProxy),
- Name: "np2",
+ exp: getModifiedExpSpec(func(np *ngfAPIv1alpha2.NginxProxy) *ngfAPIv1alpha2.NginxProxy {
+ np.Spec.Telemetry.ServiceName = helpers.GetPointer("new-service-name")
+ np.Spec.Telemetry.Exporter.Endpoint = helpers.GetPointer("new-endpoint")
+ np.Spec.Telemetry.Exporter.BatchSize = helpers.GetPointer[int32](20)
+ return np
+ }),
+ },
+ {
+ name: "gateway nginx proxy overrides select rewrite client IP values",
+ gcNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ gwNp: &NginxProxy{
+ Valid: true,
+ Source: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
+ SetIPRecursively: helpers.GetPointer(false),
+ },
},
},
},
- expNP: &NginxProxy{
- Source: &ngfAPI.NginxProxy{
- ObjectMeta: metav1.ObjectMeta{
- Name: "np2",
- },
- Spec: ngfAPI.NginxProxySpec{
- IPFamily: helpers.GetPointer(ngfAPI.Dual),
+ exp: getModifiedExpSpec(func(np *ngfAPIv1alpha2.NginxProxy) *ngfAPIv1alpha2.NginxProxy {
+ np.Spec.RewriteClientIP.Mode = helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol)
+ np.Spec.RewriteClientIP.SetIPRecursively = helpers.GetPointer(false)
+ return np
+ }),
+ },
+ {
+ name: "gateway nginx proxy unsets slices values",
+ gcNp: &NginxProxy{Valid: true, Source: getNginxProxy()},
+ gwNp: &NginxProxy{
+ Valid: true,
+ Source: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ DisabledFeatures: []ngfAPIv1alpha2.DisableTelemetryFeature{},
+ SpanAttributes: []ngfAPIv1alpha1.SpanAttribute{},
+ },
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ TrustedAddresses: []ngfAPIv1alpha2.Address{},
+ },
},
},
- Valid: true,
},
- name: "returns correct resource",
+ exp: getModifiedExpSpec(func(np *ngfAPIv1alpha2.NginxProxy) *ngfAPIv1alpha2.NginxProxy {
+ np.Spec.RewriteClientIP.TrustedAddresses = []ngfAPIv1alpha2.Address{}
+ np.Spec.Telemetry.DisabledFeatures = []ngfAPIv1alpha2.DisableTelemetryFeature{}
+ np.Spec.Telemetry.SpanAttributes = []ngfAPIv1alpha1.SpanAttribute{}
+ return np
+ }),
},
}
@@ -87,64 +290,71 @@ func TestGetNginxProxy(t *testing.T) {
t.Parallel()
g := NewWithT(t)
- g.Expect(buildNginxProxy(test.nps, test.gc, &validationfakes.FakeGenericValidator{})).To(Equal(test.expNP))
+ enp := buildEffectiveNginxProxy(test.gcNp, test.gwNp)
+ g.Expect(enp).To(Equal(test.exp))
})
}
}
-func TestIsNginxProxyReferenced(t *testing.T) {
+func TestTelemetryEnabledForNginxProxy(t *testing.T) {
t.Parallel()
+
tests := []struct {
- gc *GatewayClass
- npName types.NamespacedName
- name string
- expRes bool
+ ep *EffectiveNginxProxy
+ name string
+ enabled bool
}{
{
- gc: &GatewayClass{
- Source: &v1.GatewayClass{
- Spec: v1.GatewayClassSpec{
- ParametersRef: &v1.ParametersReference{
- Group: ngfAPI.GroupName,
- Kind: v1.Kind(kinds.NginxProxy),
- Name: "nginx-proxy",
- },
- },
+ name: "telemetry struct is nil",
+ ep: &EffectiveNginxProxy{
+ Telemetry: nil,
+ },
+ enabled: false,
+ },
+ {
+ name: "telemetry exporter is nil",
+ ep: &EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: nil,
},
},
- npName: types.NamespacedName{},
- expRes: false,
- name: "nil nginxproxy",
+ enabled: false,
},
{
- gc: nil,
- npName: types.NamespacedName{Name: "nginx-proxy"},
- expRes: false,
- name: "nil gatewayclass",
+ name: "tracing is disabled",
+ ep: &EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ DisabledFeatures: []ngfAPIv1alpha2.DisableTelemetryFeature{
+ ngfAPIv1alpha2.DisableTracing,
+ },
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("new-endpoint"),
+ },
+ },
+ },
+ enabled: false,
},
{
- gc: &GatewayClass{
- Source: nil,
+ name: "exporter endpoint is nil",
+ ep: &EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: nil,
+ },
+ },
},
- npName: types.NamespacedName{Name: "nginx-proxy"},
- expRes: false,
- name: "nil gatewayclass source",
+ enabled: false,
},
{
- gc: &GatewayClass{
- Source: &v1.GatewayClass{
- Spec: v1.GatewayClassSpec{
- ParametersRef: &v1.ParametersReference{
- Group: ngfAPI.GroupName,
- Kind: v1.Kind(kinds.NginxProxy),
- Name: "nginx-proxy",
- },
+ name: "normal case; enabled",
+ ep: &EffectiveNginxProxy{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("new-endpoint"),
},
},
},
- npName: types.NamespacedName{Name: "nginx-proxy"},
- expRes: true,
- name: "references the NginxProxy",
+ enabled: true,
},
}
@@ -153,7 +363,162 @@ func TestIsNginxProxyReferenced(t *testing.T) {
t.Parallel()
g := NewWithT(t)
- g.Expect(isNginxProxyReferenced(test.npName, test.gc)).To(Equal(test.expRes))
+ enabled := telemetryEnabledForNginxProxy(test.ep)
+ g.Expect(enabled).To(Equal(test.enabled))
+ })
+ }
+}
+
+func TestProcessNginxProxies(t *testing.T) {
+ t.Parallel()
+
+ gatewayClassNpName := types.NamespacedName{Namespace: "gc-ns", Name: "gc-np"}
+ gatewayNpName := types.NamespacedName{Namespace: "gw-ns", Name: "gw-np"}
+ unreferencedNpName := types.NamespacedName{Namespace: "test", Name: "unref"}
+
+ getTestNp := func(nsname types.NamespacedName) *ngfAPIv1alpha2.NginxProxy {
+ return &ngfAPIv1alpha2.NginxProxy{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: nsname.Namespace,
+ Name: nsname.Name,
+ },
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ ServiceName: helpers.GetPointer("service-name"),
+ },
+ },
+ }
+ }
+
+ gateway := &v1.Gateway{
+ ObjectMeta: metav1.ObjectMeta{
+ Namespace: "gw-ns",
+ },
+ Spec: v1.GatewaySpec{
+ Infrastructure: &v1.GatewayInfrastructure{
+ ParametersRef: &v1.LocalParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: gatewayNpName.Name,
+ },
+ },
+ },
+ }
+
+ gatewayClass := &v1.GatewayClass{
+ Spec: v1.GatewayClassSpec{
+ ParametersRef: &v1.ParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: gatewayClassNpName.Name,
+ Namespace: helpers.GetPointer[v1.Namespace]("gc-ns"),
+ },
+ },
+ }
+
+ gatewayClassRefMissingNs := &v1.GatewayClass{
+ Spec: v1.GatewayClassSpec{
+ ParametersRef: &v1.ParametersReference{
+ Group: ngfAPIv1alpha2.GroupName,
+ Kind: kinds.NginxProxy,
+ Name: gatewayClassNpName.Name,
+ },
+ },
+ }
+
+ getNpMap := func() map[types.NamespacedName]*ngfAPIv1alpha2.NginxProxy {
+ return map[types.NamespacedName]*ngfAPIv1alpha2.NginxProxy{
+ gatewayClassNpName: getTestNp(gatewayClassNpName),
+ gatewayNpName: getTestNp(gatewayNpName),
+ unreferencedNpName: getTestNp(unreferencedNpName),
+ }
+ }
+
+ getExpResult := func(valid bool) map[types.NamespacedName]*NginxProxy {
+ var errMsgs field.ErrorList
+ if !valid {
+ errMsgs = field.ErrorList{
+ field.Invalid(field.NewPath("spec.telemetry.serviceName"), "service-name", "error"),
+ }
+ }
+
+ return map[types.NamespacedName]*NginxProxy{
+ gatewayNpName: {
+ Valid: valid,
+ ErrMsgs: errMsgs,
+ Source: getTestNp(gatewayNpName),
+ },
+ gatewayClassNpName: {
+ Valid: valid,
+ ErrMsgs: errMsgs,
+ Source: getTestNp(gatewayClassNpName),
+ },
+ }
+ }
+
+ tests := []struct {
+ validator validation.GenericValidator
+ nps map[types.NamespacedName]*ngfAPIv1alpha2.NginxProxy
+ gc *v1.GatewayClass
+ gw *v1.Gateway
+ expResult map[types.NamespacedName]*NginxProxy
+ name string
+ }{
+ {
+ name: "no nginx proxies",
+ nps: nil,
+ gc: gatewayClass,
+ gw: gateway,
+ validator: createValidValidator(),
+ expResult: nil,
+ },
+ {
+ name: "gateway class param ref is missing namespace",
+ nps: map[types.NamespacedName]*ngfAPIv1alpha2.NginxProxy{
+ gatewayClassNpName: getTestNp(gatewayClassNpName),
+ gatewayNpName: getTestNp(gatewayNpName),
+ },
+ gc: gatewayClassRefMissingNs,
+ gw: gateway,
+ validator: createValidValidator(),
+ expResult: map[types.NamespacedName]*NginxProxy{
+ gatewayNpName: {
+ Valid: true,
+ Source: getTestNp(gatewayNpName),
+ },
+ },
+ },
+ {
+ name: "normal case; both nginx proxies are valid",
+ nps: getNpMap(),
+ gc: gatewayClass,
+ gw: gateway,
+ validator: createValidValidator(),
+ expResult: getExpResult(true),
+ },
+ {
+ name: "normal case; both nginx proxies are invalid",
+ nps: getNpMap(),
+ gc: gatewayClass,
+ gw: gateway,
+ validator: createInvalidValidator(),
+ expResult: getExpResult(false),
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
+ g := NewWithT(t)
+
+ result := processNginxProxies(
+ test.nps,
+ test.validator,
+ test.gc,
+ test.gw,
+ )
+
+ g.Expect(helpers.Diff(test.expResult, result)).To(BeEmpty())
})
}
}
@@ -194,7 +559,7 @@ func TestGCReferencesAnyNginxProxy(t *testing.T) {
gc: &v1.GatewayClass{
Spec: v1.GatewayClassSpec{
ParametersRef: &v1.ParametersReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha2.GroupName,
Kind: v1.Kind("WrongKind"),
Name: "wrong-kind",
},
@@ -207,7 +572,7 @@ func TestGCReferencesAnyNginxProxy(t *testing.T) {
gc: &v1.GatewayClass{
Spec: v1.GatewayClassSpec{
ParametersRef: &v1.ParametersReference{
- Group: ngfAPI.GroupName,
+ Group: ngfAPIv1alpha2.GroupName,
Kind: v1.Kind(kinds.NginxProxy),
Name: "nginx-proxy",
},
@@ -228,30 +593,95 @@ func TestGCReferencesAnyNginxProxy(t *testing.T) {
}
}
-func createValidValidator() *validationfakes.FakeGenericValidator {
- v := &validationfakes.FakeGenericValidator{}
- v.ValidateEscapedStringNoVarExpansionReturns(nil)
- v.ValidateEndpointReturns(nil)
- v.ValidateServiceNameReturns(nil)
- v.ValidateNginxDurationReturns(nil)
-
- return v
-}
+func TestGWReferencesAnyNginxProxy(t *testing.T) {
+ t.Parallel()
+ tests := []struct {
+ gw *v1.Gateway
+ name string
+ expRes bool
+ }{
+ {
+ gw: nil,
+ expRes: false,
+ name: "nil gateway",
+ },
+ {
+ gw: &v1.Gateway{
+ Spec: v1.GatewaySpec{},
+ },
+ expRes: false,
+ name: "nil infrastructure",
+ },
+ {
+ gw: &v1.Gateway{
+ Spec: v1.GatewaySpec{
+ Infrastructure: &v1.GatewayInfrastructure{},
+ },
+ },
+ expRes: false,
+ name: "nil parametersRef",
+ },
+ {
+ gw: &v1.Gateway{
+ Spec: v1.GatewaySpec{
+ Infrastructure: &v1.GatewayInfrastructure{
+ ParametersRef: &v1.LocalParametersReference{
+ Group: v1.Group("wrong-group"),
+ Kind: v1.Kind(kinds.NginxProxy),
+ Name: "wrong-group",
+ },
+ },
+ },
+ },
+ expRes: false,
+ name: "wrong group name",
+ },
+ {
+ gw: &v1.Gateway{
+ Spec: v1.GatewaySpec{
+ Infrastructure: &v1.GatewayInfrastructure{
+ ParametersRef: &v1.LocalParametersReference{
+ Group: v1.Group(ngfAPIv1alpha2.GroupName),
+ Kind: v1.Kind("wrong-kind"),
+ Name: "wrong-kind",
+ },
+ },
+ },
+ },
+ expRes: false,
+ name: "wrong kind",
+ },
+ {
+ gw: &v1.Gateway{
+ Spec: v1.GatewaySpec{
+ Infrastructure: &v1.GatewayInfrastructure{
+ ParametersRef: &v1.LocalParametersReference{
+ Group: v1.Group(ngfAPIv1alpha2.GroupName),
+ Kind: v1.Kind(kinds.NginxProxy),
+ Name: "normal",
+ },
+ },
+ },
+ },
+ expRes: true,
+ name: "references an NginxProxy",
+ },
+ }
-func createInvalidValidator() *validationfakes.FakeGenericValidator {
- v := &validationfakes.FakeGenericValidator{}
- v.ValidateEscapedStringNoVarExpansionReturns(errors.New("error"))
- v.ValidateEndpointReturns(errors.New("error"))
- v.ValidateServiceNameReturns(errors.New("error"))
- v.ValidateNginxDurationReturns(errors.New("error"))
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
+ g := NewWithT(t)
- return v
+ g.Expect(gwReferencesAnyNginxProxy(test.gw)).To(Equal(test.expRes))
+ })
+ }
}
func TestValidateNginxProxy(t *testing.T) {
t.Parallel()
tests := []struct {
- np *ngfAPI.NginxProxy
+ np *ngfAPIv1alpha2.NginxProxy
validator *validationfakes.FakeGenericValidator
name string
expErrSubstring string
@@ -260,36 +690,36 @@ func TestValidateNginxProxy(t *testing.T) {
{
name: "valid nginxproxy",
validator: createValidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
ServiceName: helpers.GetPointer("my-svc"),
- Exporter: &ngfAPI.TelemetryExporter{
- Interval: helpers.GetPointer[ngfAPI.Duration]("5ms"),
- Endpoint: "my-endpoint",
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Interval: helpers.GetPointer[ngfAPIv1alpha1.Duration]("5ms"),
+ Endpoint: helpers.GetPointer("my-endpoint"),
},
- SpanAttributes: []ngfAPI.SpanAttribute{
+ SpanAttributes: []ngfAPIv1alpha1.SpanAttribute{
{Key: "key", Value: "value"},
},
},
- IPFamily: helpers.GetPointer[ngfAPI.IPFamilyType](ngfAPI.Dual),
- RewriteClientIP: &ngfAPI.RewriteClientIP{
+ IPFamily: helpers.GetPointer[ngfAPIv1alpha2.IPFamilyType](ngfAPIv1alpha2.Dual),
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
SetIPRecursively: helpers.GetPointer(true),
- TrustedAddresses: []ngfAPI.Address{
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
{
- Type: ngfAPI.CIDRAddressType,
+ Type: ngfAPIv1alpha2.CIDRAddressType,
Value: "2001:db8:a0b:12f0::1/32",
},
{
- Type: ngfAPI.IPAddressType,
+ Type: ngfAPIv1alpha2.IPAddressType,
Value: "1.1.1.1",
},
{
- Type: ngfAPI.HostnameAddressType,
+ Type: ngfAPIv1alpha2.HostnameAddressType,
Value: "example.com",
},
},
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
},
},
},
@@ -298,9 +728,9 @@ func TestValidateNginxProxy(t *testing.T) {
{
name: "invalid serviceName",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
ServiceName: helpers.GetPointer("my-svc"), // any value is invalid by the validator
},
},
@@ -311,11 +741,11 @@ func TestValidateNginxProxy(t *testing.T) {
{
name: "invalid endpoint",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- Exporter: &ngfAPI.TelemetryExporter{
- Endpoint: "my-endpoint", // any value is invalid by the validator
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Endpoint: helpers.GetPointer("my-endpoint"), // any value is invalid by the validator
},
},
},
@@ -326,11 +756,11 @@ func TestValidateNginxProxy(t *testing.T) {
{
name: "invalid interval",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- Exporter: &ngfAPI.TelemetryExporter{
- Interval: helpers.GetPointer[ngfAPI.Duration](
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ Exporter: &ngfAPIv1alpha2.TelemetryExporter{
+ Interval: helpers.GetPointer[ngfAPIv1alpha1.Duration](
"my-interval",
), // any value is invalid by the validator
},
@@ -343,10 +773,10 @@ func TestValidateNginxProxy(t *testing.T) {
{
name: "invalid spanAttributes",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{
- SpanAttributes: []ngfAPI.SpanAttribute{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{
+ SpanAttributes: []ngfAPIv1alpha1.SpanAttribute{
{Key: "my-key", Value: "my-value"}, // any value is invalid by the validator
},
},
@@ -358,10 +788,10 @@ func TestValidateNginxProxy(t *testing.T) {
{
name: "invalid ipFamily type",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Telemetry: &ngfAPI.Telemetry{},
- IPFamily: helpers.GetPointer[ngfAPI.IPFamilyType]("invalid"),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Telemetry: &ngfAPIv1alpha2.Telemetry{},
+ IPFamily: helpers.GetPointer[ngfAPIv1alpha2.IPFamilyType]("invalid"),
},
},
expErrSubstring: "spec.ipFamily",
@@ -386,7 +816,7 @@ func TestValidateNginxProxy(t *testing.T) {
func TestValidateRewriteClientIP(t *testing.T) {
t.Parallel()
tests := []struct {
- np *ngfAPI.NginxProxy
+ np *ngfAPIv1alpha2.NginxProxy
validator *validationfakes.FakeGenericValidator
name string
errorString string
@@ -395,33 +825,33 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "valid rewriteClientIP",
validator: createValidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
SetIPRecursively: helpers.GetPointer(true),
- TrustedAddresses: []ngfAPI.Address{
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
{
- Type: ngfAPI.CIDRAddressType,
+ Type: ngfAPIv1alpha2.CIDRAddressType,
Value: "2001:db8:a0b:12f0::1/32",
},
{
- Type: ngfAPI.CIDRAddressType,
+ Type: ngfAPIv1alpha2.CIDRAddressType,
Value: "10.56.32.11/32",
},
{
- Type: ngfAPI.IPAddressType,
+ Type: ngfAPIv1alpha2.IPAddressType,
Value: "1.1.1.1",
},
{
- Type: ngfAPI.IPAddressType,
+ Type: ngfAPIv1alpha2.IPAddressType,
Value: "2001:db8:a0b:12f0::1",
},
{
- Type: ngfAPI.HostnameAddressType,
+ Type: ngfAPIv1alpha2.HostnameAddressType,
Value: "example.com",
},
},
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
},
},
},
@@ -430,21 +860,21 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "invalid CIDR in trustedAddresses",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
SetIPRecursively: helpers.GetPointer(true),
- TrustedAddresses: []ngfAPI.Address{
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
{
- Type: ngfAPI.CIDRAddressType,
+ Type: ngfAPIv1alpha2.CIDRAddressType,
Value: "2001:db8::/129",
},
{
- Type: ngfAPI.CIDRAddressType,
+ Type: ngfAPIv1alpha2.CIDRAddressType,
Value: "10.0.0.1/32",
},
},
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
},
},
},
@@ -455,21 +885,21 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "invalid IP address in trustedAddresses",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
SetIPRecursively: helpers.GetPointer(true),
- TrustedAddresses: []ngfAPI.Address{
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
{
- Type: ngfAPI.IPAddressType,
+ Type: ngfAPIv1alpha2.IPAddressType,
Value: "1.2.3.4.5",
},
{
- Type: ngfAPI.IPAddressType,
+ Type: ngfAPIv1alpha2.IPAddressType,
Value: "10.0.0.1",
},
},
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
},
},
},
@@ -480,21 +910,21 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "invalid hostname in trustedAddresses",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
SetIPRecursively: helpers.GetPointer(true),
- TrustedAddresses: []ngfAPI.Address{
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
{
- Type: ngfAPI.HostnameAddressType,
+ Type: ngfAPIv1alpha2.HostnameAddressType,
Value: "bad-host$%^",
},
{
- Type: ngfAPI.HostnameAddressType,
+ Type: ngfAPIv1alpha2.HostnameAddressType,
Value: "example.com",
},
},
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
},
},
},
@@ -507,10 +937,10 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "invalid when mode is set and trustedAddresses is empty",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
},
},
},
@@ -520,32 +950,32 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "invalid when trustedAddresses is greater in length than 16",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
- TrustedAddresses: []ngfAPI.Address{
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
- {Type: ngfAPI.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
+ {Type: ngfAPIv1alpha2.CIDRAddressType, Value: "2001:db8:a0b:12f0::1/32"},
},
},
},
@@ -556,17 +986,17 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "invalid when mode is not proxyProtocol or XForwardedFor",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeType("invalid")),
- TrustedAddresses: []ngfAPI.Address{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeType("invalid")),
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
{
- Type: ngfAPI.CIDRAddressType,
+ Type: ngfAPIv1alpha2.CIDRAddressType,
Value: "2001:db8:a0b:12f0::1/32",
},
{
- Type: ngfAPI.CIDRAddressType,
+ Type: ngfAPIv1alpha2.CIDRAddressType,
Value: "10.0.0.1/32",
},
},
@@ -580,10 +1010,10 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "invalid when mode is not proxyProtocol or XForwardedFor and trustedAddresses is empty",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeType("invalid")),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeType("invalid")),
},
},
},
@@ -595,17 +1025,17 @@ func TestValidateRewriteClientIP(t *testing.T) {
{
name: "invalid address type in trustedAddresses",
validator: createInvalidValidator(),
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- RewriteClientIP: &ngfAPI.RewriteClientIP{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ RewriteClientIP: &ngfAPIv1alpha2.RewriteClientIP{
SetIPRecursively: helpers.GetPointer(true),
- TrustedAddresses: []ngfAPI.Address{
+ TrustedAddresses: []ngfAPIv1alpha2.Address{
{
- Type: ngfAPI.AddressType("invalid"),
+ Type: ngfAPIv1alpha2.AddressType("invalid"),
Value: "2001:db8::/129",
},
},
- Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol),
+ Mode: helpers.GetPointer(ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol),
},
},
},
@@ -631,19 +1061,19 @@ func TestValidateRewriteClientIP(t *testing.T) {
func TestValidateLogging(t *testing.T) {
t.Parallel()
- invalidLogLevel := ngfAPI.NginxErrorLogLevel("invalid-log-level")
+ invalidLogLevel := ngfAPIv1alpha2.NginxErrorLogLevel("invalid-log-level")
tests := []struct {
- np *ngfAPI.NginxProxy
+ np *ngfAPIv1alpha2.NginxProxy
name string
errorString string
expectErrCount int
}{
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
- ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelDebug),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelDebug),
},
},
},
@@ -652,10 +1082,10 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 0,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
- ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelInfo),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelInfo),
},
},
},
@@ -664,10 +1094,10 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 0,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
- ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelNotice),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelNotice),
},
},
},
@@ -676,10 +1106,10 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 0,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
- ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelWarn),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelWarn),
},
},
},
@@ -688,10 +1118,10 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 0,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
- ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelError),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError),
},
},
},
@@ -700,10 +1130,10 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 0,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
- ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelCrit),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelCrit),
},
},
},
@@ -712,10 +1142,10 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 0,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
- ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelAlert),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelAlert),
},
},
},
@@ -724,10 +1154,10 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 0,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
- ErrorLevel: helpers.GetPointer(ngfAPI.NginxLogLevelEmerg),
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
+ ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelEmerg),
},
},
},
@@ -736,9 +1166,9 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 0,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{
ErrorLevel: &invalidLogLevel,
},
},
@@ -749,9 +1179,9 @@ func TestValidateLogging(t *testing.T) {
expectErrCount: 1,
},
{
- np: &ngfAPI.NginxProxy{
- Spec: ngfAPI.NginxProxySpec{
- Logging: &ngfAPI.NginxLogging{},
+ np: &ngfAPIv1alpha2.NginxProxy{
+ Spec: ngfAPIv1alpha2.NginxProxySpec{
+ Logging: &ngfAPIv1alpha2.NginxLogging{},
},
},
name: "empty log level",
@@ -773,3 +1203,11 @@ func TestValidateLogging(t *testing.T) {
})
}
}
+
+func TestValidateNginxProxy_NilCase(t *testing.T) {
+ t.Parallel()
+ g := NewWithT(t)
+
+ // Just testing the nil case for coverage reasons. The rest of the function is covered by other tests.
+ g.Expect(buildNginxProxy(nil, &validationfakes.FakeGenericValidator{})).To(BeNil())
+}
diff --git a/internal/mode/static/state/graph/route_common.go b/internal/mode/static/state/graph/route_common.go
index 4b2e767c67..3c8227f37d 100644
--- a/internal/mode/static/state/graph/route_common.go
+++ b/internal/mode/static/state/graph/route_common.go
@@ -187,7 +187,7 @@ func buildL4RoutesForGateways(
tlsRoutes map[types.NamespacedName]*v1alpha.TLSRoute,
gatewayNsNames []types.NamespacedName,
services map[types.NamespacedName]*apiv1.Service,
- npCfg *NginxProxy,
+ npCfg *EffectiveNginxProxy,
resolver *referenceGrantResolver,
) map[L4RouteKey]*L4Route {
if len(gatewayNsNames) == 0 {
@@ -216,7 +216,7 @@ func buildRoutesForGateways(
httpRoutes map[types.NamespacedName]*v1.HTTPRoute,
grpcRoutes map[types.NamespacedName]*v1.GRPCRoute,
gatewayNsNames []types.NamespacedName,
- npCfg *NginxProxy,
+ effectiveNginxProxy *EffectiveNginxProxy,
snippetsFilters map[types.NamespacedName]*SnippetsFilter,
) map[RouteKey]*L7Route {
if len(gatewayNsNames) == 0 {
@@ -225,7 +225,7 @@ func buildRoutesForGateways(
routes := make(map[RouteKey]*L7Route)
- http2disabled := isHTTP2Disabled(npCfg)
+ http2disabled := isHTTP2Disabled(effectiveNginxProxy)
for _, route := range httpRoutes {
r := buildHTTPRoute(validator, route, gatewayNsNames, snippetsFilters)
@@ -244,11 +244,16 @@ func buildRoutesForGateways(
return routes
}
-func isHTTP2Disabled(npCfg *NginxProxy) bool {
+func isHTTP2Disabled(npCfg *EffectiveNginxProxy) bool {
if npCfg == nil {
return false
}
- return npCfg.Source.Spec.DisableHTTP2
+
+ if npCfg.DisableHTTP2 == nil {
+ return false
+ }
+
+ return *npCfg.DisableHTTP2
}
func buildSectionNameRefs(
diff --git a/internal/mode/static/state/graph/tlsroute.go b/internal/mode/static/state/graph/tlsroute.go
index 03a8ca8a36..ec59f5058a 100644
--- a/internal/mode/static/state/graph/tlsroute.go
+++ b/internal/mode/static/state/graph/tlsroute.go
@@ -15,7 +15,7 @@ func buildTLSRoute(
gtr *v1alpha2.TLSRoute,
gatewayNsNames []types.NamespacedName,
services map[types.NamespacedName]*apiv1.Service,
- npCfg *NginxProxy,
+ npCfg *EffectiveNginxProxy,
refGrantResolver func(resource toResource) bool,
) *L4Route {
r := &L4Route{
@@ -69,7 +69,7 @@ func buildTLSRoute(
func validateBackendRefTLSRoute(gtr *v1alpha2.TLSRoute,
services map[types.NamespacedName]*apiv1.Service,
- npCfg *NginxProxy,
+ npCfg *EffectiveNginxProxy,
refGrantResolver func(resource toResource) bool,
) (BackendRef, *conditions.Condition) {
// Length of BackendRefs and Rules is guaranteed to be one due to earlier check in buildTLSRoute
diff --git a/internal/mode/static/state/graph/tlsroute_test.go b/internal/mode/static/state/graph/tlsroute_test.go
index edd6536ace..ff6ee787f2 100644
--- a/internal/mode/static/state/graph/tlsroute_test.go
+++ b/internal/mode/static/state/graph/tlsroute_test.go
@@ -10,7 +10,7 @@ import (
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
"sigs.k8s.io/gateway-api/apis/v1alpha2"
- ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
+ ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha2"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
staticConds "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/conditions"
@@ -271,9 +271,9 @@ func TestBuildTLSRoute(t *testing.T) {
gtr *v1alpha2.TLSRoute
services map[types.NamespacedName]*apiv1.Service
resolver func(resource toResource) bool
+ npCfg *EffectiveNginxProxy
name string
gatewayNsNames []types.NamespacedName
- npCfg NginxProxy
}{
{
gtr: duplicateParentRefsGtr,
@@ -491,10 +491,7 @@ func TestBuildTLSRoute(t *testing.T) {
services: map[types.NamespacedName]*apiv1.Service{
svcNsName: ipv4Svc,
},
- npCfg: NginxProxy{
- Source: &ngfAPI.NginxProxy{Spec: ngfAPI.NginxProxySpec{IPFamily: helpers.GetPointer(ngfAPI.IPv6)}},
- Valid: true,
- },
+ npCfg: &EffectiveNginxProxy{IPFamily: helpers.GetPointer(ngfAPI.IPv6)},
resolver: alwaysTrueRefGrantResolver,
name: "service and npcfg ip family mismatch",
},
@@ -559,7 +556,7 @@ func TestBuildTLSRoute(t *testing.T) {
test.gtr,
test.gatewayNsNames,
test.services,
- &test.npCfg,
+ test.npCfg,
test.resolver,
)
g.Expect(helpers.Diff(test.expected, r)).To(BeEmpty())
diff --git a/internal/mode/static/status/prepare_requests.go b/internal/mode/static/status/prepare_requests.go
index e0add956a8..df8586151b 100644
--- a/internal/mode/static/status/prepare_requests.go
+++ b/internal/mode/static/status/prepare_requests.go
@@ -293,6 +293,8 @@ func prepareGatewayRequest(
}
gwConds := staticConds.NewDefaultGatewayConditions()
+ gwConds = append(gwConds, gateway.Conditions...)
+
if validListenerCount == 0 {
gwConds = append(gwConds, staticConds.NewGatewayNotAcceptedListenersNotValid()...)
} else if validListenerCount < len(gateway.Listeners) {
diff --git a/internal/mode/static/status/prepare_requests_test.go b/internal/mode/static/status/prepare_requests_test.go
index d52b43e7a8..510b4e756b 100644
--- a/internal/mode/static/status/prepare_requests_test.go
+++ b/internal/mode/static/status/prepare_requests_test.go
@@ -1134,6 +1134,117 @@ func TestBuildGatewayStatuses(t *testing.T) {
},
nginxReloadRes: NginxReloadResult{Error: errors.New("test error")},
},
+ {
+ name: "valid gateway with valid parametersRef; all valid listeners",
+ gateway: &graph.Gateway{
+ Source: createGateway(),
+ Listeners: []*graph.Listener{
+ {
+ Name: "listener-valid-1",
+ Valid: true,
+ Routes: map[graph.RouteKey]*graph.L7Route{routeKey: {}},
+ },
+ },
+ Valid: true,
+ Conditions: []conditions.Condition{
+ staticConds.NewGatewayResolvedRefs(),
+ },
+ },
+ expected: map[types.NamespacedName]v1.GatewayStatus{
+ {Namespace: "test", Name: "gateway"}: {
+ Addresses: addr,
+ Conditions: []metav1.Condition{
+ {
+ Type: string(v1.GatewayConditionAccepted),
+ Status: metav1.ConditionTrue,
+ ObservedGeneration: 2,
+ LastTransitionTime: transitionTime,
+ Reason: string(v1.GatewayReasonAccepted),
+ Message: "Gateway is accepted",
+ },
+ {
+ Type: string(v1.GatewayConditionProgrammed),
+ Status: metav1.ConditionTrue,
+ ObservedGeneration: 2,
+ LastTransitionTime: transitionTime,
+ Reason: string(v1.GatewayReasonProgrammed),
+ Message: "Gateway is programmed",
+ },
+ {
+ Type: string(staticConds.GatewayResolvedRefs),
+ Status: metav1.ConditionTrue,
+ ObservedGeneration: 2,
+ LastTransitionTime: transitionTime,
+ Reason: string(staticConds.GatewayReasonResolvedRefs),
+ Message: "ParametersRef resource is resolved",
+ },
+ },
+ Listeners: []v1.ListenerStatus{
+ {
+ Name: "listener-valid-1",
+ AttachedRoutes: 1,
+ Conditions: validListenerConditions,
+ },
+ },
+ },
+ },
+ },
+ {
+ name: "valid gateway with invalid parametersRef; all valid listeners",
+ gateway: &graph.Gateway{
+ Source: createGateway(),
+ Listeners: []*graph.Listener{
+ {
+ Name: "listener-valid-1",
+ Valid: true,
+ Routes: map[graph.RouteKey]*graph.L7Route{routeKey: {}},
+ },
+ },
+ Valid: true,
+ Conditions: []conditions.Condition{
+ staticConds.NewGatewayRefNotFound(),
+ staticConds.NewGatewayInvalidParameters("ParametersRef not found"),
+ },
+ },
+ expected: map[types.NamespacedName]v1.GatewayStatus{
+ {Namespace: "test", Name: "gateway"}: {
+ Addresses: addr,
+ Conditions: []metav1.Condition{
+ {
+ Type: string(v1.GatewayConditionProgrammed),
+ Status: metav1.ConditionTrue,
+ ObservedGeneration: 2,
+ LastTransitionTime: transitionTime,
+ Reason: string(v1.GatewayReasonProgrammed),
+ Message: "Gateway is programmed",
+ },
+ {
+ Type: string(staticConds.GatewayResolvedRefs),
+ Status: metav1.ConditionFalse,
+ ObservedGeneration: 2,
+ LastTransitionTime: transitionTime,
+ Reason: string(staticConds.GatewayReasonParamsRefNotFound),
+ Message: "ParametersRef resource could not be found",
+ },
+ {
+ Type: string(v1.GatewayConditionAccepted),
+ Status: metav1.ConditionTrue,
+ ObservedGeneration: 2,
+ LastTransitionTime: transitionTime,
+ Reason: string(v1.GatewayReasonInvalidParameters),
+ Message: "Gateway is accepted, but ParametersRef is ignored due to an error: ParametersRef not found",
+ },
+ },
+ Listeners: []v1.ListenerStatus{
+ {
+ Name: "listener-valid-1",
+ AttachedRoutes: 1,
+ Conditions: validListenerConditions,
+ },
+ },
+ },
+ },
+ },
}
for _, test := range tests {
diff --git a/internal/mode/static/telemetry/collector.go b/internal/mode/static/telemetry/collector.go
index d809ab342c..e334216e14 100644
--- a/internal/mode/static/telemetry/collector.go
+++ b/internal/mode/static/telemetry/collector.go
@@ -246,10 +246,7 @@ func collectGraphResourceCount(
}
}
- if g.NginxProxy != nil {
- ngfResourceCounts.NginxProxyCount = 1
- }
-
+ ngfResourceCounts.NginxProxyCount = int64(len(g.ReferencedNginxProxies))
ngfResourceCounts.SnippetsFilterCount = int64(len(g.SnippetsFilters))
return ngfResourceCounts, nil
diff --git a/internal/mode/static/telemetry/collector_test.go b/internal/mode/static/telemetry/collector_test.go
index 5a7b11b582..93a3ba616b 100644
--- a/internal/mode/static/telemetry/collector_test.go
+++ b/internal/mode/static/telemetry/collector_test.go
@@ -334,8 +334,10 @@ var _ = Describe("Collector", Ordered, func() {
GVK: schema.GroupVersionKind{Kind: kinds.UpstreamSettingsPolicy},
}: {},
},
- NginxProxy: &graph.NginxProxy{},
- SnippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{
+ ReferencedNginxProxies: map[types.NamespacedName]*graph.NginxProxy{
+ {Namespace: "test", Name: "NginxProxy-1"}: {},
+ {Namespace: "test", Name: "NginxProxy-2"}: {},
+ }, SnippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{
{Namespace: "test", Name: "sf-1"}: {
Snippets: map[ngfAPI.NginxContext]string{
ngfAPI.NginxContextMain: "worker_priority 0;",
@@ -414,7 +416,7 @@ var _ = Describe("Collector", Ordered, func() {
GatewayAttachedClientSettingsPolicyCount: 1,
RouteAttachedClientSettingsPolicyCount: 2,
ObservabilityPolicyCount: 1,
- NginxProxyCount: 1,
+ NginxProxyCount: 2,
SnippetsFilterCount: 3,
UpstreamSettingsPolicyCount: 1,
}
@@ -613,7 +615,10 @@ var _ = Describe("Collector", Ordered, func() {
GVK: schema.GroupVersionKind{Kind: kinds.UpstreamSettingsPolicy},
}: {},
},
- NginxProxy: &graph.NginxProxy{},
+ ReferencedNginxProxies: map[types.NamespacedName]*graph.NginxProxy{
+ {Namespace: "test", Name: "NginxProxy-1"}: {},
+ {Namespace: "test", Name: "NginxProxy-2"}: {},
+ },
SnippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{
{Namespace: "test", Name: "sf-1"}: {},
},
@@ -689,7 +694,7 @@ var _ = Describe("Collector", Ordered, func() {
GatewayAttachedClientSettingsPolicyCount: 1,
RouteAttachedClientSettingsPolicyCount: 1,
ObservabilityPolicyCount: 1,
- NginxProxyCount: 1,
+ NginxProxyCount: 2,
SnippetsFilterCount: 1,
UpstreamSettingsPolicyCount: 1,
}
diff --git a/site/content/how-to/data-plane-configuration.md b/site/content/how-to/data-plane-configuration.md
index 1db8f26632..8466732dc3 100644
--- a/site/content/how-to/data-plane-configuration.md
+++ b/site/content/how-to/data-plane-configuration.md
@@ -69,7 +69,7 @@ The following command creates a basic `NginxProxy` configuration that sets the I
```yaml
kubectl apply -f - <
@@ -22,8 +25,6 @@ Resource Types:
- NginxProxy is a configuration object that is attached to a GatewayClass parametersRef. It provides a way
-to configure global settings for all Gateways defined from the GatewayClass.gateway.nginx.org/v1alpha1
NginxProxy
-¶
-
-
Field | -Description | -||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
-apiVersion -string |
-
-
-gateway.nginx.org/v1alpha1
-
- |
-||||||||||
-kind -string - |
-NginxProxy |
-||||||||||
-metadata - - -Kubernetes meta/v1.ObjectMeta - - - |
-
-Refer to the Kubernetes API documentation for the fields of the
-metadata field.
- |
-||||||||||
-spec - - -NginxProxySpec - - - |
-
- Spec defines the desired state of the NginxProxy. -- -
|
-
-(Appears on: -RewriteClientIP) -
--
Address is a struct that specifies address type and value.
- -Field | -Description | -
---|---|
-type - - -AddressType - - - |
-
- Type specifies the type of address. - |
-
-value - -string - - |
-
- Value specifies the address value. - |
-
string
alias)¶
--(Appears on: -Address) -
--
AddressType specifies the type of address.
- -Value | -Description | -
---|---|
"CIDR" |
-CIDRAddressType specifies that the address is a CIDR block. - |
-
"Hostname" |
-HostnameAddressType specifies that the address is a Hostname. - |
-
"IPAddress" |
-IPAddressType specifies that the address is an IP address. - |
-
Duration is a string value representing a duration in time. @@ -1110,34 +904,6 @@ Duration can be specified in milliseconds (ms), seconds (s), minutes (m), hours A value without a suffix is seconds. Examples: 120s, 50ms, 5m, 1h.
-string
alias)¶
--(Appears on: -NginxProxySpec) -
--
IPFamilyType specifies the IP family to be used by NGINX.
- -Value | -Description | -
---|---|
"dual" |
-Dual specifies that NGINX will use both IPv4 and IPv6. - |
-
"ipv4" |
-IPv4 specifies that NGINX will use only IPv4. - |
-
"ipv6" |
-IPv6 specifies that NGINX will use only IPv6. - |
-
string
alias)¶
+string
alias)¶
-(Appears on: -NginxLogging) -
--
NginxErrorLogLevel type defines the log level of error logs for NGINX.
+NginxGatewayConditionReason defines the set of reasons that explain why a +particular NginxGateway condition type has been raised.
Description | -|
---|---|
"alert" |
-NginxLogLevelAlert is the alert level for NGINX error logs. - |
-
"crit" |
-NginxLogLevelCrit is the crit level for NGINX error logs. - |
-
"debug" |
-NginxLogLevelDebug is the debug level for NGINX error logs. - |
-
"emerg" |
-NginxLogLevelEmerg is the emerg level for NGINX error logs. - |
-
"error" |
-NginxLogLevelError is the error level for NGINX error logs. - |
-
"info" |
-NginxLogLevelInfo is the info level for NGINX error logs. - |
-
"notice" |
-NginxLogLevelNotice is the notice level for NGINX error logs. + |
"Invalid" |
+NginxGatewayReasonInvalid is a reason that is used with the “Valid” condition when the condition is False. |
-
"warn" |
-NginxLogLevelWarn is the warn level for NGINX error logs. + |
"Valid" |
+NginxGatewayReasonValid is a reason that is used with the “Valid” condition when the condition is True. |
string
alias)¶
--
NginxGatewayConditionReason defines the set of reasons that explain why a -particular NginxGateway condition type has been raised.
- -Value | -Description | -
---|---|
"Invalid" |
-NginxGatewayReasonInvalid is a reason that is used with the “Valid” condition when the condition is False. - |
-
"Valid" |
-NginxGatewayReasonValid is a reason that is used with the “Valid” condition when the condition is True. - |
-
string
alias)¶
+string
alias)¶
NginxGatewayConditionType is a type of condition associated with an @@ -1358,133 +1081,6 @@ Logging -
-(Appears on: -NginxProxySpec) -
--
NginxLogging defines logging related settings for NGINX.
- -Field | -Description | -
---|---|
-errorLevel - - -NginxErrorLogLevel - - - |
-
-(Optional)
- ErrorLevel defines the error log level. Possible log levels listed in order of increasing severity are -debug, info, notice, warn, error, crit, alert, and emerg. Setting a certain log level will cause all messages -of the specified and more severe log levels to be logged. For example, the log level ‘error’ will cause error, -crit, alert, and emerg messages to be logged. https://nginx.org/en/docs/ngx_core_module.html#error_log - |
-
-(Appears on: -NginxProxy) -
--
NginxProxySpec defines the desired state of the NginxProxy.
- -Field | -Description | -
---|---|
-ipFamily - - -IPFamilyType - - - |
-
-(Optional)
- IPFamily specifies the IP family to be used by the NGINX. -Default is “dual”, meaning the server will use both IPv4 and IPv6. - |
-
-telemetry - - -Telemetry - - - |
-
-(Optional)
- Telemetry specifies the OpenTelemetry configuration. - |
-
-rewriteClientIP - - -RewriteClientIP - - - |
-
-(Optional)
- RewriteClientIP defines configuration for rewriting the client IP to the original client’s IP. - |
-
-logging - - -NginxLogging - - - |
-
-(Optional)
- Logging defines logging related settings for NGINX. - |
-
-disableHTTP2 - -bool - - |
-
-(Optional)
- DisableHTTP2 defines if http2 should be disabled for all servers. -Default is false, meaning http2 will be enabled for all servers. - |
-
-(Appears on: -NginxProxySpec) -
--
RewriteClientIP specifies the configuration for rewriting the client’s IP address.
- -Field | -Description | -
---|---|
-mode - - -RewriteClientIPModeType - - - |
-
-(Optional)
- Mode defines how NGINX will rewrite the client’s IP address. -There are two possible modes: -- ProxyProtocol: NGINX will rewrite the client’s IP using the PROXY protocol header. -- XForwardedFor: NGINX will rewrite the client’s IP using the X-Forwarded-For header. -Sets NGINX directive real_ip_header: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header - |
-
-setIPRecursively - -bool - - |
-
-(Optional)
- SetIPRecursively configures whether recursive search is used when selecting the client’s address from -the X-Forwarded-For header. It is used in conjunction with TrustedAddresses. -If enabled, NGINX will recurse on the values in X-Forwarded-Header from the end of array -to start of array and select the first untrusted IP. -For example, if X-Forwarded-For is [11.11.11.11, 22.22.22.22, 55.55.55.1], -and TrustedAddresses is set to 55.55.55.1⁄32, NGINX will rewrite the client IP to 22.22.22.22. -If disabled, NGINX will select the IP at the end of the array. -In the previous example, 55.55.55.1 would be selected. -Sets NGINX directive real_ip_recursive: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_recursive - |
-
-trustedAddresses - - -[]Address - - - |
-
-(Optional)
- TrustedAddresses specifies the addresses that are trusted to send correct client IP information. -If a request comes from a trusted address, NGINX will rewrite the client IP information, -and forward it to the backend in the X-Forwarded-For* and X-Real-IP headers. -If the request does not come from a trusted address, NGINX will not rewrite the client IP information. -TrustedAddresses only supports CIDR blocks: 192.33.21.1⁄24, fe80::1⁄64. -To trust all addresses (not recommended for production), set to 0.0.0.0/0. -If no addresses are provided, NGINX will not rewrite the client IP information. -Sets NGINX directive set_real_ip_from: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from -This field is required if mode is set. - |
-
string
alias)¶
--(Appears on: -RewriteClientIP) -
--
RewriteClientIPModeType defines how NGINX Gateway Fabric will determine the client’s original IP address.
- -Value | -Description | -
---|---|
"ProxyProtocol" |
-RewriteClientIPModeProxyProtocol configures NGINX to accept PROXY protocol and -set the client’s IP address to the IP address in the PROXY protocol header. -Sets the proxy_protocol parameter on the listen directive of all servers and sets real_ip_header -to proxy_protocol: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header. - |
-
"XForwardedFor" |
-RewriteClientIPModeXForwardedFor configures NGINX to set the client’s IP address to the -IP address in the X-Forwarded-For HTTP header. -https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header. - |
-
string
alias)¶
(Appears on: -Telemetry, -Tracing) +Tracing, +Telemetry)
SpanAttribute is a key value pair to be added to a tracing span.
@@ -1864,155 +1350,20 @@ Format: must have all ‘“’ escaped and must not contain any &ls -string
alias)¶
(Appears on: -NginxProxySpec) +Tracing)
-
Telemetry specifies the OpenTelemetry configuration.
+TraceContext specifies how to propagate traceparent/tracestate headers.
Field | -Description | -
---|---|
-exporter - - -TelemetryExporter - - - |
-
-(Optional)
- Exporter specifies OpenTelemetry export parameters. - |
-
-serviceName - -string - - |
-
-(Optional)
- ServiceName is the “service.name” attribute of the OpenTelemetry resource.
-Default is ‘ngf: |
-
-spanAttributes - - -[]SpanAttribute - - - |
-
-(Optional)
- SpanAttributes are custom key/value attributes that are added to each span. - |
-
-(Appears on: -Telemetry) -
--
TelemetryExporter specifies OpenTelemetry export parameters.
- -Field | -Description | -
---|---|
-interval - - -Duration - - - |
-
-(Optional)
- Interval is the maximum interval between two exports. -Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter - |
-
-batchSize - -int32 - - |
-
-(Optional)
- BatchSize is the maximum number of spans to be sent in one batch per worker. -Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter - |
-
-batchCount - -int32 - - |
-
-(Optional)
- BatchCount is the number of pending batches per worker, spans exceeding the limit are dropped. -Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter - |
-
-endpoint - -string - - |
-
- Endpoint is the address of OTLP/gRPC endpoint that will accept telemetry data. -Format: alphanumeric hostname with optional http scheme and optional port. - |
-
string
alias)¶
--(Appears on: -Tracing) -
--
TraceContext specifies how to propagate traceparent/tracestate headers.
- -Value | +Value | Description |
---|
+
Package v1alpha2 contains API Schema definitions for the +gateway.nginx.org API group.
+ +Resource Types: ++
NginxProxy is a configuration object that can be referenced from a GatewayClass parametersRef +or a Gateway infrastructure.parametersRef. It provides a way to configure data plane settings. +If referenced from a GatewayClass, the settings apply to all Gateways attached to the GatewayClass. +If referenced from a Gateway, the settings apply to that Gateway alone. If both a Gateway and its GatewayClass +reference an NginxProxy, the settings are merged. Settings specified on the Gateway NginxProxy override those +set on the GatewayClass NginxProxy.
+ +Field | +Description | +||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
+apiVersion +string |
+
+
+gateway.nginx.org/v1alpha2
+
+ |
+||||||||||
+kind +string + |
+NginxProxy |
+||||||||||
+metadata + + +Kubernetes meta/v1.ObjectMeta + + + |
+
+Refer to the Kubernetes API documentation for the fields of the
+metadata field.
+ |
+||||||||||
+spec + + +NginxProxySpec + + + |
+
+ Spec defines the desired state of the NginxProxy. ++ +
|
+
+(Appears on: +RewriteClientIP) +
++
Address is a struct that specifies address type and value.
+ +Field | +Description | +
---|---|
+type + + +AddressType + + + |
+
+ Type specifies the type of address. + |
+
+value + +string + + |
+
+ Value specifies the address value. + |
+
string
alias)¶
++(Appears on: +Address) +
++
AddressType specifies the type of address.
+ +Value | +Description | +
---|---|
"CIDR" |
+CIDRAddressType specifies that the address is a CIDR block. + |
+
"Hostname" |
+HostnameAddressType specifies that the address is a Hostname. + |
+
"IPAddress" |
+IPAddressType specifies that the address is an IP address. + |
+
string
alias)¶
++(Appears on: +Telemetry) +
++
DisableTelemetryFeature is a telemetry feature that can be disabled.
+ +Value | +Description | +
---|---|
"DisableTracing" |
+DisableTracing disables the OpenTelemetry tracing feature. + |
+
string
alias)¶
++(Appears on: +NginxProxySpec) +
++
IPFamilyType specifies the IP family to be used by NGINX.
+ +Value | +Description | +
---|---|
"dual" |
+Dual specifies that NGINX will use both IPv4 and IPv6. + |
+
"ipv4" |
+IPv4 specifies that NGINX will use only IPv4. + |
+
"ipv6" |
+IPv6 specifies that NGINX will use only IPv6. + |
+
string
alias)¶
++(Appears on: +NginxLogging) +
++
NginxErrorLogLevel type defines the log level of error logs for NGINX.
+ +Value | +Description | +
---|---|
"alert" |
+NginxLogLevelAlert is the alert level for NGINX error logs. + |
+
"crit" |
+NginxLogLevelCrit is the crit level for NGINX error logs. + |
+
"debug" |
+NginxLogLevelDebug is the debug level for NGINX error logs. + |
+
"emerg" |
+NginxLogLevelEmerg is the emerg level for NGINX error logs. + |
+
"error" |
+NginxLogLevelError is the error level for NGINX error logs. + |
+
"info" |
+NginxLogLevelInfo is the info level for NGINX error logs. + |
+
"notice" |
+NginxLogLevelNotice is the notice level for NGINX error logs. + |
+
"warn" |
+NginxLogLevelWarn is the warn level for NGINX error logs. + |
+
+(Appears on: +NginxProxySpec) +
++
NginxLogging defines logging related settings for NGINX.
+ +Field | +Description | +
---|---|
+errorLevel + + +NginxErrorLogLevel + + + |
+
+(Optional)
+ ErrorLevel defines the error log level. Possible log levels listed in order of increasing severity are +debug, info, notice, warn, error, crit, alert, and emerg. Setting a certain log level will cause all messages +of the specified and more severe log levels to be logged. For example, the log level ‘error’ will cause error, +crit, alert, and emerg messages to be logged. https://nginx.org/en/docs/ngx_core_module.html#error_log + |
+
+(Appears on: +NginxProxy) +
++
NginxProxySpec defines the desired state of the NginxProxy.
+ +Field | +Description | +
---|---|
+ipFamily + + +IPFamilyType + + + |
+
+(Optional)
+ IPFamily specifies the IP family to be used by the NGINX. +Default is “dual”, meaning the server will use both IPv4 and IPv6. + |
+
+telemetry + + +Telemetry + + + |
+
+(Optional)
+ Telemetry specifies the OpenTelemetry configuration. + |
+
+rewriteClientIP + + +RewriteClientIP + + + |
+
+(Optional)
+ RewriteClientIP defines configuration for rewriting the client IP to the original client’s IP. + |
+
+logging + + +NginxLogging + + + |
+
+(Optional)
+ Logging defines logging related settings for NGINX. + |
+
+disableHTTP2 + +bool + + |
+
+(Optional)
+ DisableHTTP2 defines if http2 should be disabled for all servers. +If not specified, or set to false, http2 will be enabled for all servers. + |
+
+(Appears on: +NginxProxySpec) +
++
RewriteClientIP specifies the configuration for rewriting the client’s IP address.
+ +Field | +Description | +
---|---|
+mode + + +RewriteClientIPModeType + + + |
+
+(Optional)
+ Mode defines how NGINX will rewrite the client’s IP address. +There are two possible modes: +- ProxyProtocol: NGINX will rewrite the client’s IP using the PROXY protocol header. +- XForwardedFor: NGINX will rewrite the client’s IP using the X-Forwarded-For header. +Sets NGINX directive real_ip_header: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header + |
+
+setIPRecursively + +bool + + |
+
+(Optional)
+ SetIPRecursively configures whether recursive search is used when selecting the client’s address from +the X-Forwarded-For header. It is used in conjunction with TrustedAddresses. +If enabled, NGINX will recurse on the values in X-Forwarded-Header from the end of array +to start of array and select the first untrusted IP. +For example, if X-Forwarded-For is [11.11.11.11, 22.22.22.22, 55.55.55.1], +and TrustedAddresses is set to 55.55.55.1⁄32, NGINX will rewrite the client IP to 22.22.22.22. +If disabled, NGINX will select the IP at the end of the array. +In the previous example, 55.55.55.1 would be selected. +Sets NGINX directive real_ip_recursive: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_recursive + |
+
+trustedAddresses + + +[]Address + + + |
+
+(Optional)
+ TrustedAddresses specifies the addresses that are trusted to send correct client IP information. +If a request comes from a trusted address, NGINX will rewrite the client IP information, +and forward it to the backend in the X-Forwarded-For* and X-Real-IP headers. +If the request does not come from a trusted address, NGINX will not rewrite the client IP information. +To trust all addresses (not recommended for production), set to 0.0.0.0/0. +If no addresses are provided, NGINX will not rewrite the client IP information. +Sets NGINX directive set_real_ip_from: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from +This field is required if mode is set. + |
+
string
alias)¶
++(Appears on: +RewriteClientIP) +
++
RewriteClientIPModeType defines how NGINX Gateway Fabric will determine the client’s original IP address.
+ +Value | +Description | +
---|---|
"ProxyProtocol" |
+RewriteClientIPModeProxyProtocol configures NGINX to accept PROXY protocol and +set the client’s IP address to the IP address in the PROXY protocol header. +Sets the proxy_protocol parameter on the listen directive of all servers and sets real_ip_header +to proxy_protocol: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header. + |
+
"XForwardedFor" |
+RewriteClientIPModeXForwardedFor configures NGINX to set the client’s IP address to the +IP address in the X-Forwarded-For HTTP header. +https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header. + |
+
+(Appears on: +NginxProxySpec) +
++
Telemetry specifies the OpenTelemetry configuration.
+ +Field | +Description | +
---|---|
+disabledFeatures + + +[]DisableTelemetryFeature + + + |
+
+(Optional)
+ DisabledFeatures specifies OpenTelemetry features to be disabled. + |
+
+exporter + + +TelemetryExporter + + + |
+
+(Optional)
+ Exporter specifies OpenTelemetry export parameters. + |
+
+serviceName + +string + + |
+
+(Optional)
+ ServiceName is the “service.name” attribute of the OpenTelemetry resource.
+Default is ‘ngf: |
+
+spanAttributes + + +[]SpanAttribute + + + |
+
+(Optional)
+ SpanAttributes are custom key/value attributes that are added to each span. + |
+
+(Appears on: +Telemetry) +
++
TelemetryExporter specifies OpenTelemetry export parameters.
+ +Field | +Description | +
---|---|
+interval + + +Duration + + + |
+
+(Optional)
+ Interval is the maximum interval between two exports. +Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter + |
+
+batchSize + +int32 + + |
+
+(Optional)
+ BatchSize is the maximum number of spans to be sent in one batch per worker. +Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter + |
+
+batchCount + +int32 + + |
+
+(Optional)
+ BatchCount is the number of pending batches per worker, spans exceeding the limit are dropped. +Default: https://nginx.org/en/docs/ngx_otel_module.html#otel_exporter + |
+
+endpoint + +string + + |
+
+(Optional)
+ Endpoint is the address of OTLP/gRPC endpoint that will accept telemetry data. +Format: alphanumeric hostname with optional http scheme and optional port. + |
+
Generated with gen-crd-api-reference-docs