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