Skip to content
Merged
8 changes: 8 additions & 0 deletions internal/configs/config_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ type ConfigParams struct {
UseClusterIP bool
VariablesHashBucketSize uint64
VariablesHashMaxSize uint64
ZoneSync ZoneSync

RealIPHeader string
RealIPRecursive bool
Expand Down Expand Up @@ -175,6 +176,13 @@ type Listener struct {
Protocol string
}

// ZoneSync holds zone sync values for state sharing.
type ZoneSync struct {
Enable bool
Port int
Domain string
}

// MGMTSecrets holds mgmt block secret names
type MGMTSecrets struct {
License string
Expand Down
50 changes: 50 additions & 0 deletions internal/configs/configmaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"context"
"errors"
"fmt"
"os"
"strings"
"time"

Expand Down Expand Up @@ -399,6 +400,47 @@
}
}

if zoneSync, exists, err := GetMapKeyAsBool(cfgm.Data, "zone-sync", cfgm); exists {
if err != nil {
nl.Error(l, err)
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, err.Error())
configOk = false

Check warning on line 407 in internal/configs/configmaps.go

View check run for this annotation

Codecov / codecov/patch

internal/configs/configmaps.go#L405-L407

Added lines #L405 - L407 were not covered by tests
} else {
if nginxPlus {
cfgParams.ZoneSync.Enable = zoneSync
} else {
errorText := fmt.Sprintf("ConfigMap %s/%s key %s requires NGINX Plus", cfgm.Namespace, cfgm.Name, "zone-sync")
nl.Warn(l, errorText)
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, errorText)
configOk = false
}

Check warning on line 416 in internal/configs/configmaps.go

View check run for this annotation

Codecov / codecov/patch

internal/configs/configmaps.go#L412-L416

Added lines #L412 - L416 were not covered by tests
}
}

if zoneSyncPort, exists, err := GetMapKeyAsInt(cfgm.Data, "zone-sync-port", cfgm); exists {
if err != nil {
nl.Error(l, err)
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, err.Error())
configOk = false
} else {
if cfgParams.ZoneSync.Enable {
portValidationError := validation.ValidatePort(zoneSyncPort)
if portValidationError != nil {
nl.Error(l, portValidationError)
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, portValidationError.Error())
configOk = false

Check warning on line 431 in internal/configs/configmaps.go

View check run for this annotation

Codecov / codecov/patch

internal/configs/configmaps.go#L429-L431

Added lines #L429 - L431 were not covered by tests
} else {
cfgParams.ZoneSync.Port = zoneSyncPort
}
} else {
errorText := fmt.Sprintf("ConfigMap %s/%s key %s requires 'zone-sync' to be enabled", cfgm.Namespace, cfgm.Name, "zone-sync-port")
nl.Warn(l, errorText)
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, errorText)
configOk = false
}
}
}

if upstreamZoneSize, exists := cfgm.Data["upstream-zone-size"]; exists {
cfgParams.UpstreamZoneSize = upstreamZoneSize
}
Expand Down Expand Up @@ -777,6 +819,13 @@
}
}

podNamespace := os.Getenv("POD_NAMESPACE")
zoneSyncConfig := version1.ZoneSyncConfig{
Enable: config.ZoneSync.Enable,
Port: config.ZoneSync.Port,
Domain: fmt.Sprintf("%s-headless.%s.svc.cluster.local", podNamespace, podNamespace),
}

nginxCfg := &version1.MainConfig{
AccessLog: config.MainAccessLog,
DefaultServerAccessLogOff: config.DefaultServerAccessLogOff,
Expand Down Expand Up @@ -850,6 +899,7 @@
InternalRouteServerName: staticCfgParams.InternalRouteServerName,
LatencyMetrics: staticCfgParams.EnableLatencyMetrics,
OIDC: staticCfgParams.EnableOIDC,
ZoneSyncConfig: zoneSyncConfig,
DynamicSSLReloadEnabled: staticCfgParams.DynamicSSLReload,
StaticSSLPath: staticCfgParams.StaticSSLPath,
NginxVersion: staticCfgParams.NginxVersion,
Expand Down
187 changes: 187 additions & 0 deletions internal/configs/configmaps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package configs

import (
"context"
"fmt"
"os"
"testing"

"github.com/nginx/kubernetes-ingress/internal/configs/version1"

v1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/record"
)
Expand Down Expand Up @@ -788,6 +792,189 @@ func TestParseMGMTConfigMapUsageReportEndpoint(t *testing.T) {
}
}

func TestParseZoneSync(t *testing.T) {
t.Parallel()
tests := []struct {
configMap *v1.ConfigMap
want *ZoneSync
msg string
}{
{
configMap: &v1.ConfigMap{
Data: map[string]string{
"zone-sync": "true",
},
},
want: &ZoneSync{
Enable: true,
},
msg: "zone-sync set to true",
},
{
configMap: &v1.ConfigMap{
Data: map[string]string{
"zone-sync": "false",
},
},
want: &ZoneSync{
Enable: false,
},
msg: "zone-sync set to false",
},
}

for _, test := range tests {
t.Run(test.msg, func(t *testing.T) {
result, _ := ParseConfigMap(context.Background(), test.configMap, true, false, false, false, makeEventLogger())
if result.ZoneSync.Enable != test.want.Enable {
t.Errorf("Enable: want %v, got %v", test.want.Enable, result.ZoneSync)
}
})
}
}

func TestParseZoneSyncPort(t *testing.T) {
t.Parallel()
tests := []struct {
configMap *v1.ConfigMap
want *ZoneSync
msg string
}{
{
configMap: &v1.ConfigMap{
Data: map[string]string{
"zone-sync": "true",
"zone-sync-port": "1234",
},
},
want: &ZoneSync{
Enable: true,
Port: 1234,
},
msg: "zone-sync-port set to 1234",
},
}

nginxPlus := true
hasAppProtect := true
hasAppProtectDos := false
hasTLSPassthrough := false

for _, test := range tests {
t.Run(test.msg, func(t *testing.T) {
result, _ := ParseConfigMap(context.Background(), test.configMap, nginxPlus, hasAppProtect, hasAppProtectDos, hasTLSPassthrough, makeEventLogger())
if result.ZoneSync.Port != test.want.Port {
t.Errorf("Port: want %v, got %v", test.want.Port, result.ZoneSync.Port)
}
})
}
}

func TestParseZoneSyncPortErrors(t *testing.T) {
t.Parallel()
tests := []struct {
configMap *v1.ConfigMap
configOk bool
msg string
}{
{
configMap: &v1.ConfigMap{
Data: map[string]string{
"zone-sync-port": "0",
},
},
configOk: false,
msg: "port out of range (0)",
},
{
configMap: &v1.ConfigMap{
Data: map[string]string{
"zone-sync-port": "-1",
},
},
configOk: false,
msg: "port out of range (negative)",
},
{
configMap: &v1.ConfigMap{
Data: map[string]string{
"zone-sync-port": "65536",
},
},
configOk: false,
msg: "port out of range (greater than 65535)",
},
{
configMap: &v1.ConfigMap{
Data: map[string]string{
"zone-sync-port": "not-a-number",
},
},
configOk: false,
msg: "invalid non-numeric port",
},
{
configMap: &v1.ConfigMap{
Data: map[string]string{
"zone-sync-port": "",
},
},
configOk: false,
msg: "missing port value",
},
}

nginxPlus := true
hasAppProtect := true
hasAppProtectDos := false
hasTLSPassthrough := false

for _, test := range tests {
t.Run(test.msg, func(t *testing.T) {
_, err := ParseConfigMap(context.Background(), test.configMap, nginxPlus, hasAppProtect, hasAppProtectDos, hasTLSPassthrough, makeEventLogger())
if err == !test.configOk {
t.Error("Expected error, got nil")
}
})
}
}

func TestZoneSyncDomainMultipleNamespaces(t *testing.T) {
testCases := []struct {
name string
namespace string
want string
}{
{
name: "nginx-ingress",
namespace: "nginx-ingress",
want: "nginx-ingress-headless.nginx-ingress.svc.cluster.local",
},
{
name: "my-release-nginx-ingress",
namespace: "my-release-nginx-ingress",
want: "my-release-nginx-ingress-headless.my-release-nginx-ingress.svc.cluster.local",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
_ = os.Setenv("POD_NAMESPACE", tc.namespace)

zoneSyncConfig := version1.ZoneSyncConfig{
Enable: true,
Domain: fmt.Sprintf("%s-headless.%s.svc.cluster.local",
os.Getenv("POD_NAMESPACE"),
os.Getenv("POD_NAMESPACE")),
}

if zoneSyncConfig.Domain != tc.want {
t.Errorf("want %q, got %q", tc.want, zoneSyncConfig.Domain)
}
})
}
}

func makeEventLogger() record.EventRecorder {
return record.NewFakeRecorder(1024)
}
8 changes: 8 additions & 0 deletions internal/configs/version1/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ type Location struct {
MinionIngress *Ingress
}

// ZoneSyncConfig is tbe configuration for the zone_sync directives for state sharing.
type ZoneSyncConfig struct {
Enable bool
Port int
Domain string
}

// MGMTConfig is tbe configuration for the MGMT block.
type MGMTConfig struct {
SSLVerify *bool
Expand Down Expand Up @@ -276,6 +283,7 @@ type MainConfig struct {
InternalRouteServer bool
InternalRouteServerName string
LatencyMetrics bool
ZoneSyncConfig ZoneSyncConfig
OIDC bool
DynamicSSLReloadEnabled bool
StaticSSLPath string
Expand Down
Loading