kube-proxy: refactor config validation unit test

Refactor the TestValidateKubeProxyConfiguration by adding a mutating
function that adjusts the configuration according to each test case,
thereby enhancing readability.

Signed-off-by: Daman Arora <aroradaman@gmail.com>
This commit is contained in:
Daman Arora 2024-02-19 14:12:26 +05:30 committed by Dan Winship
parent f4ecae8324
commit a577c0b324

View File

@ -28,526 +28,176 @@ import (
componentbaseconfig "k8s.io/component-base/config" componentbaseconfig "k8s.io/component-base/config"
logsapi "k8s.io/component-base/logs/api/v1" logsapi "k8s.io/component-base/logs/api/v1"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config" kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
"k8s.io/utils/ptr" "k8s.io/utils/ptr"
) )
func TestValidateKubeProxyConfiguration(t *testing.T) { func TestValidateKubeProxyConfiguration(t *testing.T) {
var proxyMode kubeproxyconfig.ProxyMode baseConfig := &kubeproxyconfig.KubeProxyConfiguration{
if runtime.GOOS == "windows" { BindAddress: "192.168.59.103",
proxyMode = kubeproxyconfig.ProxyModeKernelspace HealthzBindAddress: "0.0.0.0:10256",
} else { MetricsBindAddress: "127.0.0.1:10249",
proxyMode = kubeproxyconfig.ProxyModeIPVS ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
} }
newPath := field.NewPath("KubeProxyConfiguration") newPath := field.NewPath("KubeProxyConfiguration")
for name, testCase := range map[string]struct { for name, testCase := range map[string]struct {
config kubeproxyconfig.KubeProxyConfiguration mutateConfigFunc func(*kubeproxyconfig.KubeProxyConfiguration)
expectedErrs field.ErrorList expectedErrs field.ErrorList
}{ }{
"Mode specified, extra mode-specific configs": {
config: kubeproxyconfig.KubeProxyConfiguration{
BindAddress: "192.168.59.103",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Mode: proxyMode,
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
},
},
"basic config, unspecified Mode": { "basic config, unspecified Mode": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(_ *kubeproxyconfig.KubeProxyConfiguration) {},
BindAddress: "192.168.59.103", },
HealthzBindAddress: "0.0.0.0:10256", "Mode specified, extra mode-specific configs": {
MetricsBindAddress: "127.0.0.1:10249", mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
ClusterCIDR: "192.168.59.0/24", if runtime.GOOS == "windows" {
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second}, config.Mode = kubeproxyconfig.ProxyModeKernelspace
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{ } else {
MasqueradeAll: true, config.Mode = kubeproxyconfig.ProxyModeIPVS
SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, config.IPVS = kubeproxyconfig.KubeProxyIPVSConfiguration{
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
}, MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ }
MaxPerCore: ptr.To[int32](1), }
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
}, },
"empty HealthzBindAddress": { "empty HealthzBindAddress": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "192.168.59.103", config.HealthzBindAddress = ""
HealthzBindAddress: "",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
}, },
"IPv6": { "IPv6": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "fd00:192:168:59::103", config.BindAddress = "fd00:192:168:59::103"
HealthzBindAddress: "", config.HealthzBindAddress = ""
MetricsBindAddress: "[::1]:10249", config.MetricsBindAddress = "[::1]:10249"
ClusterCIDR: "fd00:192:168:59::/64", config.ClusterCIDR = "fd00:192:168:59::/64"
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
}, },
"alternate healthz port": { "alternate healthz port": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.HealthzBindAddress = "0.0.0.0:12345"
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
}, },
"ClusterCIDR is wrong IP family": { "ClusterCIDR is wrong IP family": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.ClusterCIDR = "fd00:192:168::/64"
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "fd00:192:168::/64",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
}, },
"ClusterCIDR is dual-stack": { "ClusterCIDR is dual-stack": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.ClusterCIDR = "192.168.59.0/24,fd00:192:168::/64"
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24,fd00:192:168::/64",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
}, },
"LocalModeInterfaceNamePrefix": { "LocalModeInterfaceNamePrefix": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.DetectLocalMode = kubeproxyconfig.LocalModeInterfaceNamePrefix
HealthzBindAddress: "0.0.0.0:12345", config.DetectLocal = kubeproxyconfig.DetectLocalConfiguration{
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: kubeproxyconfig.LocalModeInterfaceNamePrefix,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "vethabcde", InterfaceNamePrefix: "vethabcde",
}, }
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
}, },
"LocalModeBridgeInterface": { "LocalModeBridgeInterface": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.DetectLocalMode = kubeproxyconfig.LocalModeBridgeInterface
HealthzBindAddress: "0.0.0.0:12345", config.DetectLocal = kubeproxyconfig.DetectLocalConfiguration{
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: kubeproxyconfig.LocalModeBridgeInterface,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
BridgeInterface: "avz", BridgeInterface: "avz",
}, }
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
}, },
"invalid BindAddress": { "invalid BindAddress": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11:2000", config.BindAddress = "10.10.12.11:2000"
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("BindAddress"), "10.10.12.11:2000", "not a valid textual representation of an IP address")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("BindAddress"), "10.10.12.11:2000", "not a valid textual representation of an IP address")},
}, },
"invalid HealthzBindAddress": { "invalid HealthzBindAddress": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.HealthzBindAddress = "0.0.0.0"
HealthzBindAddress: "0.0.0.0",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("HealthzBindAddress"), "0.0.0.0", "must be IP:port")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("HealthzBindAddress"), "0.0.0.0", "must be IP:port")},
}, },
"invalid MetricsBindAddress": { "invalid MetricsBindAddress": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.MetricsBindAddress = "127.0.0.1"
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("MetricsBindAddress"), "127.0.0.1", "must be IP:port")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("MetricsBindAddress"), "127.0.0.1", "must be IP:port")},
}, },
"ClusterCIDR missing subset range": { "ClusterCIDR missing subset range": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.ClusterCIDR = "192.168.59.0"
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")},
}, },
"Invalid number of ClusterCIDRs": { "Invalid number of ClusterCIDRs": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.ClusterCIDR = "192.168.59.0/24,fd00:192:168::/64,10.0.0.0/16"
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24,fd00:192:168::/64,10.0.0.0/16",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0/24,fd00:192:168::/64,10.0.0.0/16", "only one CIDR allowed or a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0/24,fd00:192:168::/64,10.0.0.0/16", "only one CIDR allowed or a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)")},
}, },
"ConfigSyncPeriod must be > 0": { "ConfigSyncPeriod must be > 0": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.ConfigSyncPeriod = metav1.Duration{Duration: -1 * time.Second}
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ConfigSyncPeriod"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than 0")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ConfigSyncPeriod"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than 0")},
}, },
"IPVS mode selected without providing required SyncPeriod": { "IPVS mode selected without providing required SyncPeriod": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "192.168.59.103", config.Mode = kubeproxyconfig.ProxyModeIPVS
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
// not specifying valid period in IPVS mode.
Mode: kubeproxyconfig.ProxyModeIPVS,
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeProxyIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 0}, "must be greater than 0")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeProxyIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 0}, "must be greater than 0")},
}, },
"interfacePrefix is empty": { "interfacePrefix is empty": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.DetectLocalMode = kubeproxyconfig.LocalModeInterfaceNamePrefix
HealthzBindAddress: "0.0.0.0:12345", config.DetectLocal = kubeproxyconfig.DetectLocalConfiguration{
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: kubeproxyconfig.LocalModeInterfaceNamePrefix,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "", InterfaceNamePrefix: "",
}, }
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("InterfacePrefix"), "", "must not be empty")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("InterfacePrefix"), "", "must not be empty")},
}, },
"bridgeInterfaceName is empty": { "bridgeInterfaceName is empty": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.DetectLocalMode = kubeproxyconfig.LocalModeBridgeInterface
HealthzBindAddress: "0.0.0.0:12345", config.DetectLocal = kubeproxyconfig.DetectLocalConfiguration{
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: kubeproxyconfig.LocalModeBridgeInterface,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "eth0", // we won't care about prefix since mode is not prefix InterfaceNamePrefix: "eth0", // we won't care about prefix since mode is not prefix
}, }
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("InterfaceName"), "", "must not be empty")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("InterfaceName"), "", "must not be empty")},
}, },
"invalid DetectLocalMode": { "invalid DetectLocalMode": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.DetectLocalMode = "Guess"
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
DetectLocalMode: "Guess",
Logging: logsapi.LoggingConfiguration{
Format: "text",
},
}, },
expectedErrs: field.ErrorList{field.NotSupported(newPath.Child("DetectLocalMode"), "Guess", []string{"ClusterCIDR", "NodeCIDR", "BridgeInterface", "InterfaceNamePrefix", ""})}, expectedErrs: field.ErrorList{field.NotSupported(newPath.Child("DetectLocalMode"), "Guess", []string{"ClusterCIDR", "NodeCIDR", "BridgeInterface", "InterfaceNamePrefix", ""})},
}, },
"invalid logging format": { "invalid logging format": {
config: kubeproxyconfig.KubeProxyConfiguration{ mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
BindAddress: "10.10.12.11", config.Logging = logsapi.LoggingConfiguration{
HealthzBindAddress: "0.0.0.0:12345",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
MasqueradeAll: true,
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
Min: ptr.To[int32](1),
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
Logging: logsapi.LoggingConfiguration{
Format: "unsupported format", Format: "unsupported format",
}, }
}, },
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("logging.format"), "unsupported format", "Unsupported log format")}, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("logging.format"), "unsupported format", "Unsupported log format")},
}, },
} { } {
if runtime.GOOS == "windows" && testCase.config.Mode == kubeproxyconfig.ProxyModeIPVS {
// IPVS is not supported on Windows.
t.Log("Skipping test on Windows: ", name)
continue
}
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
errs := Validate(&testCase.config) config := baseConfig.DeepCopy()
testCase.mutateConfigFunc(config)
errs := Validate(config)
if len(testCase.expectedErrs) == 0 { if len(testCase.expectedErrs) == 0 {
assert.Equal(t, field.ErrorList{}, errs, "expected no validation errors") assert.Equal(t, field.ErrorList{}, errs, "expected no validation errors")
} else { } else {