Skip to content

Commit e200c2b

Browse files
authored
Add initial zone_sync values to the ConfigMap (#7239)
1 parent 7698219 commit e200c2b

File tree

4 files changed

+253
-0
lines changed

4 files changed

+253
-0
lines changed

internal/configs/config_params.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type ConfigParams struct {
9090
UseClusterIP bool
9191
VariablesHashBucketSize uint64
9292
VariablesHashMaxSize uint64
93+
ZoneSync ZoneSync
9394

9495
RealIPHeader string
9596
RealIPRecursive bool
@@ -175,6 +176,13 @@ type Listener struct {
175176
Protocol string
176177
}
177178

179+
// ZoneSync holds zone sync values for state sharing.
180+
type ZoneSync struct {
181+
Enable bool
182+
Port int
183+
Domain string
184+
}
185+
178186
// MGMTSecrets holds mgmt block secret names
179187
type MGMTSecrets struct {
180188
License string

internal/configs/configmaps.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"os"
78
"strings"
89
"time"
910

@@ -399,6 +400,47 @@ func ParseConfigMap(ctx context.Context, cfgm *v1.ConfigMap, nginxPlus bool, has
399400
}
400401
}
401402

403+
if zoneSync, exists, err := GetMapKeyAsBool(cfgm.Data, "zone-sync", cfgm); exists {
404+
if err != nil {
405+
nl.Error(l, err)
406+
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, err.Error())
407+
configOk = false
408+
} else {
409+
if nginxPlus {
410+
cfgParams.ZoneSync.Enable = zoneSync
411+
} else {
412+
errorText := fmt.Sprintf("ConfigMap %s/%s key %s requires NGINX Plus", cfgm.Namespace, cfgm.Name, "zone-sync")
413+
nl.Warn(l, errorText)
414+
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, errorText)
415+
configOk = false
416+
}
417+
}
418+
}
419+
420+
if zoneSyncPort, exists, err := GetMapKeyAsInt(cfgm.Data, "zone-sync-port", cfgm); exists {
421+
if err != nil {
422+
nl.Error(l, err)
423+
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, err.Error())
424+
configOk = false
425+
} else {
426+
if cfgParams.ZoneSync.Enable {
427+
portValidationError := validation.ValidatePort(zoneSyncPort)
428+
if portValidationError != nil {
429+
nl.Error(l, portValidationError)
430+
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, portValidationError.Error())
431+
configOk = false
432+
} else {
433+
cfgParams.ZoneSync.Port = zoneSyncPort
434+
}
435+
} else {
436+
errorText := fmt.Sprintf("ConfigMap %s/%s key %s requires 'zone-sync' to be enabled", cfgm.Namespace, cfgm.Name, "zone-sync-port")
437+
nl.Warn(l, errorText)
438+
eventLog.Event(cfgm, v1.EventTypeWarning, nl.EventReasonInvalidValue, errorText)
439+
configOk = false
440+
}
441+
}
442+
}
443+
402444
if upstreamZoneSize, exists := cfgm.Data["upstream-zone-size"]; exists {
403445
cfgParams.UpstreamZoneSize = upstreamZoneSize
404446
}
@@ -777,6 +819,13 @@ func GenerateNginxMainConfig(staticCfgParams *StaticConfigParams, config *Config
777819
}
778820
}
779821

822+
podNamespace := os.Getenv("POD_NAMESPACE")
823+
zoneSyncConfig := version1.ZoneSyncConfig{
824+
Enable: config.ZoneSync.Enable,
825+
Port: config.ZoneSync.Port,
826+
Domain: fmt.Sprintf("%s-headless.%s.svc.cluster.local", podNamespace, podNamespace),
827+
}
828+
780829
nginxCfg := &version1.MainConfig{
781830
AccessLog: config.MainAccessLog,
782831
DefaultServerAccessLogOff: config.DefaultServerAccessLogOff,
@@ -850,6 +899,7 @@ func GenerateNginxMainConfig(staticCfgParams *StaticConfigParams, config *Config
850899
InternalRouteServerName: staticCfgParams.InternalRouteServerName,
851900
LatencyMetrics: staticCfgParams.EnableLatencyMetrics,
852901
OIDC: staticCfgParams.EnableOIDC,
902+
ZoneSyncConfig: zoneSyncConfig,
853903
DynamicSSLReloadEnabled: staticCfgParams.DynamicSSLReload,
854904
StaticSSLPath: staticCfgParams.StaticSSLPath,
855905
NginxVersion: staticCfgParams.NginxVersion,

internal/configs/configmaps_test.go

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ package configs
22

33
import (
44
"context"
5+
"fmt"
6+
"os"
57
"testing"
68

9+
"github.com/nginx/kubernetes-ingress/internal/configs/version1"
10+
711
v1 "k8s.io/api/core/v1"
812
"k8s.io/client-go/tools/record"
913
)
@@ -788,6 +792,189 @@ func TestParseMGMTConfigMapUsageReportEndpoint(t *testing.T) {
788792
}
789793
}
790794

795+
func TestParseZoneSync(t *testing.T) {
796+
t.Parallel()
797+
tests := []struct {
798+
configMap *v1.ConfigMap
799+
want *ZoneSync
800+
msg string
801+
}{
802+
{
803+
configMap: &v1.ConfigMap{
804+
Data: map[string]string{
805+
"zone-sync": "true",
806+
},
807+
},
808+
want: &ZoneSync{
809+
Enable: true,
810+
},
811+
msg: "zone-sync set to true",
812+
},
813+
{
814+
configMap: &v1.ConfigMap{
815+
Data: map[string]string{
816+
"zone-sync": "false",
817+
},
818+
},
819+
want: &ZoneSync{
820+
Enable: false,
821+
},
822+
msg: "zone-sync set to false",
823+
},
824+
}
825+
826+
for _, test := range tests {
827+
t.Run(test.msg, func(t *testing.T) {
828+
result, _ := ParseConfigMap(context.Background(), test.configMap, true, false, false, false, makeEventLogger())
829+
if result.ZoneSync.Enable != test.want.Enable {
830+
t.Errorf("Enable: want %v, got %v", test.want.Enable, result.ZoneSync)
831+
}
832+
})
833+
}
834+
}
835+
836+
func TestParseZoneSyncPort(t *testing.T) {
837+
t.Parallel()
838+
tests := []struct {
839+
configMap *v1.ConfigMap
840+
want *ZoneSync
841+
msg string
842+
}{
843+
{
844+
configMap: &v1.ConfigMap{
845+
Data: map[string]string{
846+
"zone-sync": "true",
847+
"zone-sync-port": "1234",
848+
},
849+
},
850+
want: &ZoneSync{
851+
Enable: true,
852+
Port: 1234,
853+
},
854+
msg: "zone-sync-port set to 1234",
855+
},
856+
}
857+
858+
nginxPlus := true
859+
hasAppProtect := true
860+
hasAppProtectDos := false
861+
hasTLSPassthrough := false
862+
863+
for _, test := range tests {
864+
t.Run(test.msg, func(t *testing.T) {
865+
result, _ := ParseConfigMap(context.Background(), test.configMap, nginxPlus, hasAppProtect, hasAppProtectDos, hasTLSPassthrough, makeEventLogger())
866+
if result.ZoneSync.Port != test.want.Port {
867+
t.Errorf("Port: want %v, got %v", test.want.Port, result.ZoneSync.Port)
868+
}
869+
})
870+
}
871+
}
872+
873+
func TestParseZoneSyncPortErrors(t *testing.T) {
874+
t.Parallel()
875+
tests := []struct {
876+
configMap *v1.ConfigMap
877+
configOk bool
878+
msg string
879+
}{
880+
{
881+
configMap: &v1.ConfigMap{
882+
Data: map[string]string{
883+
"zone-sync-port": "0",
884+
},
885+
},
886+
configOk: false,
887+
msg: "port out of range (0)",
888+
},
889+
{
890+
configMap: &v1.ConfigMap{
891+
Data: map[string]string{
892+
"zone-sync-port": "-1",
893+
},
894+
},
895+
configOk: false,
896+
msg: "port out of range (negative)",
897+
},
898+
{
899+
configMap: &v1.ConfigMap{
900+
Data: map[string]string{
901+
"zone-sync-port": "65536",
902+
},
903+
},
904+
configOk: false,
905+
msg: "port out of range (greater than 65535)",
906+
},
907+
{
908+
configMap: &v1.ConfigMap{
909+
Data: map[string]string{
910+
"zone-sync-port": "not-a-number",
911+
},
912+
},
913+
configOk: false,
914+
msg: "invalid non-numeric port",
915+
},
916+
{
917+
configMap: &v1.ConfigMap{
918+
Data: map[string]string{
919+
"zone-sync-port": "",
920+
},
921+
},
922+
configOk: false,
923+
msg: "missing port value",
924+
},
925+
}
926+
927+
nginxPlus := true
928+
hasAppProtect := true
929+
hasAppProtectDos := false
930+
hasTLSPassthrough := false
931+
932+
for _, test := range tests {
933+
t.Run(test.msg, func(t *testing.T) {
934+
_, err := ParseConfigMap(context.Background(), test.configMap, nginxPlus, hasAppProtect, hasAppProtectDos, hasTLSPassthrough, makeEventLogger())
935+
if err == !test.configOk {
936+
t.Error("Expected error, got nil")
937+
}
938+
})
939+
}
940+
}
941+
942+
func TestZoneSyncDomainMultipleNamespaces(t *testing.T) {
943+
testCases := []struct {
944+
name string
945+
namespace string
946+
want string
947+
}{
948+
{
949+
name: "nginx-ingress",
950+
namespace: "nginx-ingress",
951+
want: "nginx-ingress-headless.nginx-ingress.svc.cluster.local",
952+
},
953+
{
954+
name: "my-release-nginx-ingress",
955+
namespace: "my-release-nginx-ingress",
956+
want: "my-release-nginx-ingress-headless.my-release-nginx-ingress.svc.cluster.local",
957+
},
958+
}
959+
960+
for _, tc := range testCases {
961+
t.Run(tc.name, func(t *testing.T) {
962+
_ = os.Setenv("POD_NAMESPACE", tc.namespace)
963+
964+
zoneSyncConfig := version1.ZoneSyncConfig{
965+
Enable: true,
966+
Domain: fmt.Sprintf("%s-headless.%s.svc.cluster.local",
967+
os.Getenv("POD_NAMESPACE"),
968+
os.Getenv("POD_NAMESPACE")),
969+
}
970+
971+
if zoneSyncConfig.Domain != tc.want {
972+
t.Errorf("want %q, got %q", tc.want, zoneSyncConfig.Domain)
973+
}
974+
})
975+
}
976+
}
977+
791978
func makeEventLogger() record.EventRecorder {
792979
return record.NewFakeRecorder(1024)
793980
}

internal/configs/version1/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,13 @@ type Location struct {
189189
MinionIngress *Ingress
190190
}
191191

192+
// ZoneSyncConfig is tbe configuration for the zone_sync directives for state sharing.
193+
type ZoneSyncConfig struct {
194+
Enable bool
195+
Port int
196+
Domain string
197+
}
198+
192199
// MGMTConfig is tbe configuration for the MGMT block.
193200
type MGMTConfig struct {
194201
SSLVerify *bool
@@ -276,6 +283,7 @@ type MainConfig struct {
276283
InternalRouteServer bool
277284
InternalRouteServerName string
278285
LatencyMetrics bool
286+
ZoneSyncConfig ZoneSyncConfig
279287
OIDC bool
280288
DynamicSSLReloadEnabled bool
281289
StaticSSLPath string

0 commit comments

Comments
 (0)