mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Merge pull request #94902 from cmluciano/cml/proxyvaltesting
proxy: Restructure config validation tests to check errors
This commit is contained in:
commit
5c7ee30eaa
@ -17,9 +17,7 @@ limitations under the License.
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -188,13 +186,13 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorCases := []struct {
|
newPath := field.NewPath("KubeProxyConfiguration")
|
||||||
|
testCases := map[string]struct {
|
||||||
config kubeproxyconfig.KubeProxyConfiguration
|
config kubeproxyconfig.KubeProxyConfiguration
|
||||||
msg string
|
expectedErrs field.ErrorList
|
||||||
}{
|
}{
|
||||||
{
|
"invalid BindAddress": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
// only BindAddress is invalid
|
|
||||||
BindAddress: "10.10.12.11:2000",
|
BindAddress: "10.10.12.11:2000",
|
||||||
HealthzBindAddress: "0.0.0.0:10256",
|
HealthzBindAddress: "0.0.0.0:10256",
|
||||||
MetricsBindAddress: "127.0.0.1:10249",
|
MetricsBindAddress: "127.0.0.1:10249",
|
||||||
@ -213,12 +211,11 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "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": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "10.10.12.11",
|
BindAddress: "10.10.12.11",
|
||||||
// only HealthzBindAddress is invalid
|
|
||||||
HealthzBindAddress: "0.0.0.0",
|
HealthzBindAddress: "0.0.0.0",
|
||||||
MetricsBindAddress: "127.0.0.1:10249",
|
MetricsBindAddress: "127.0.0.1:10249",
|
||||||
ClusterCIDR: "192.168.59.0/24",
|
ClusterCIDR: "192.168.59.0/24",
|
||||||
@ -236,13 +233,12 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "must be IP:port",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("HealthzBindAddress"), "0.0.0.0", "must be IP:port")},
|
||||||
},
|
},
|
||||||
{
|
"invalid MetricsBindAddress": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "10.10.12.11",
|
BindAddress: "10.10.12.11",
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
HealthzBindAddress: "0.0.0.0:12345",
|
||||||
// only MetricsBindAddress is invalid
|
|
||||||
MetricsBindAddress: "127.0.0.1",
|
MetricsBindAddress: "127.0.0.1",
|
||||||
ClusterCIDR: "192.168.59.0/24",
|
ClusterCIDR: "192.168.59.0/24",
|
||||||
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
||||||
@ -259,14 +255,13 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "must be IP:port",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("MetricsBindAddress"), "127.0.0.1", "must be IP:port")},
|
||||||
},
|
},
|
||||||
{
|
"ClusterCIDR missing subset range": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "10.10.12.11",
|
BindAddress: "10.10.12.11",
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
HealthzBindAddress: "0.0.0.0:12345",
|
||||||
MetricsBindAddress: "127.0.0.1:10249",
|
MetricsBindAddress: "127.0.0.1:10249",
|
||||||
// only ClusterCIDR is invalid
|
|
||||||
ClusterCIDR: "192.168.59.0",
|
ClusterCIDR: "192.168.59.0",
|
||||||
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
||||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||||
@ -282,9 +277,9 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "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)")},
|
||||||
},
|
},
|
||||||
{
|
"Two ClusterCIDR addresses provided without DualStack feature-enabled": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "10.10.12.11",
|
BindAddress: "10.10.12.11",
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
HealthzBindAddress: "0.0.0.0:12345",
|
||||||
@ -306,9 +301,9 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "only one CIDR allowed (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0/24,fd00:192:168::/64", "only one CIDR allowed (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")},
|
||||||
},
|
},
|
||||||
{
|
"DualStack feature-enabled but EndpointSlice feature disabled": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "10.10.12.11",
|
BindAddress: "10.10.12.11",
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
HealthzBindAddress: "0.0.0.0:12345",
|
||||||
@ -330,58 +325,9 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "EndpointSlice feature flag must be turned on",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("FeatureGates"), map[string]bool{"EndpointSlice": false, "IPv6DualStack": true}, "EndpointSlice feature flag must be turned on when turning on DualStack")},
|
||||||
},
|
},
|
||||||
|
"Invalid number of ClusterCIDRs": {
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
||||||
BindAddress: "10.10.12.11",
|
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
|
||||||
MetricsBindAddress: "127.0.0.1:10249",
|
|
||||||
// DualStack with multiple CIDRs but only one IP family
|
|
||||||
FeatureGates: map[string]bool{"IPv6DualStack": true, "EndpointSlice": true},
|
|
||||||
ClusterCIDR: "192.168.59.0/24,10.0.0.0/16",
|
|
||||||
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
|
||||||
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: pointer.Int32Ptr(1),
|
|
||||||
Min: pointer.Int32Ptr(1),
|
|
||||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
msg: "must be a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
||||||
BindAddress: "10.10.12.11",
|
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
|
||||||
MetricsBindAddress: "127.0.0.1:10249",
|
|
||||||
// DualStack with an invalid subnet
|
|
||||||
FeatureGates: map[string]bool{"IPv6DualStack": true, "EndpointSlice": true},
|
|
||||||
ClusterCIDR: "192.168.59.0/24,fd00:192:168::/64,a.b.c.d/f",
|
|
||||||
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
|
||||||
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: pointer.Int32Ptr(1),
|
|
||||||
Min: pointer.Int32Ptr(1),
|
|
||||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
msg: "only one CIDR allowed or a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "10.10.12.11",
|
BindAddress: "10.10.12.11",
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
HealthzBindAddress: "0.0.0.0:12345",
|
||||||
@ -402,15 +348,14 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "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)")},
|
||||||
},
|
},
|
||||||
{
|
"UDPIdleTimeout must be > 0": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "10.10.12.11",
|
BindAddress: "10.10.12.11",
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
HealthzBindAddress: "0.0.0.0:12345",
|
||||||
MetricsBindAddress: "127.0.0.1:10249",
|
MetricsBindAddress: "127.0.0.1:10249",
|
||||||
ClusterCIDR: "192.168.59.0/24",
|
ClusterCIDR: "192.168.59.0/24",
|
||||||
// only UDPIdleTimeout is invalid
|
|
||||||
UDPIdleTimeout: metav1.Duration{Duration: -1 * time.Second},
|
UDPIdleTimeout: metav1.Duration{Duration: -1 * time.Second},
|
||||||
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||||
@ -425,16 +370,15 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "must be greater than 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("UDPIdleTimeout"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than 0")},
|
||||||
},
|
},
|
||||||
{
|
"ConfigSyncPeriod must be > 0": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "10.10.12.11",
|
BindAddress: "10.10.12.11",
|
||||||
HealthzBindAddress: "0.0.0.0:12345",
|
HealthzBindAddress: "0.0.0.0:12345",
|
||||||
MetricsBindAddress: "127.0.0.1:10249",
|
MetricsBindAddress: "127.0.0.1:10249",
|
||||||
ClusterCIDR: "192.168.59.0/24",
|
ClusterCIDR: "192.168.59.0/24",
|
||||||
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
||||||
// only ConfigSyncPeriod is invalid
|
|
||||||
ConfigSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
|
ConfigSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
|
||||||
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||||
MasqueradeAll: true,
|
MasqueradeAll: true,
|
||||||
@ -448,9 +392,9 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "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": {
|
||||||
config: kubeproxyconfig.KubeProxyConfiguration{
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
||||||
BindAddress: "192.168.59.103",
|
BindAddress: "192.168.59.103",
|
||||||
HealthzBindAddress: "0.0.0.0:10256",
|
HealthzBindAddress: "0.0.0.0:10256",
|
||||||
@ -472,295 +416,276 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "must be greater than 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeProxyIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 0}, "must be greater than 0")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, errorCase := range errorCases {
|
for _, testCase := range testCases {
|
||||||
if errs := Validate(&errorCase.config); len(errs) == 0 {
|
errs := Validate(&testCase.config)
|
||||||
t.Errorf("expected failure for %s", errorCase.msg)
|
if len(testCase.expectedErrs) != len(errs) {
|
||||||
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
t.Fatalf("Expected %d errors, got %d errors: %v", len(testCase.expectedErrs), len(errs), errs)
|
||||||
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
}
|
||||||
|
for i, err := range errs {
|
||||||
|
if err.Error() != testCase.expectedErrs[i].Error() {
|
||||||
|
t.Fatalf("Expected error: %s, got %s", testCase.expectedErrs[i], err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateKubeProxyIPTablesConfiguration(t *testing.T) {
|
func TestValidateKubeProxyIPTablesConfiguration(t *testing.T) {
|
||||||
valid := int32(5)
|
|
||||||
successCases := []kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
|
||||||
{
|
|
||||||
MasqueradeAll: true,
|
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MasqueradeBit: &valid,
|
|
||||||
MasqueradeAll: true,
|
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
newPath := field.NewPath("KubeProxyConfiguration")
|
newPath := field.NewPath("KubeProxyConfiguration")
|
||||||
for _, successCase := range successCases {
|
|
||||||
if errs := validateKubeProxyIPTablesConfiguration(successCase, newPath.Child("KubeProxyIPTablesConfiguration")); len(errs) != 0 {
|
|
||||||
t.Errorf("expected success: %v", errs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
invalid := int32(-10)
|
testCases := map[string]struct {
|
||||||
errorCases := []struct {
|
|
||||||
config kubeproxyconfig.KubeProxyIPTablesConfiguration
|
config kubeproxyconfig.KubeProxyIPTablesConfiguration
|
||||||
msg string
|
expectedErrs field.ErrorList
|
||||||
}{
|
}{
|
||||||
{
|
"valid iptables config": {
|
||||||
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||||
|
MasqueradeAll: true,
|
||||||
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
|
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||||
|
},
|
||||||
|
expectedErrs: field.ErrorList{},
|
||||||
|
},
|
||||||
|
"valid custom MasqueradeBit": {
|
||||||
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||||
|
MasqueradeBit: pointer.Int32Ptr(5),
|
||||||
|
MasqueradeAll: true,
|
||||||
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
|
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||||
|
},
|
||||||
|
expectedErrs: field.ErrorList{},
|
||||||
|
},
|
||||||
|
"SyncPeriod must be > 0": {
|
||||||
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||||
MasqueradeAll: true,
|
MasqueradeAll: true,
|
||||||
SyncPeriod: metav1.Duration{Duration: -5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: -5 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||||
},
|
},
|
||||||
msg: "must be greater than 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPTablesConfiguration.SyncPeriod"), metav1.Duration{Duration: -5 * time.Second}, "must be greater than 0"),
|
||||||
|
field.Invalid(newPath.Child("KubeIPTablesConfiguration.SyncPeriod"), metav1.Duration{Duration: 2 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPTablesConfiguration.MinSyncPeriod")},
|
||||||
},
|
},
|
||||||
{
|
"MinSyncPeriod must be > 0": {
|
||||||
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||||
MasqueradeBit: &valid,
|
MasqueradeBit: pointer.Int32Ptr(5),
|
||||||
MasqueradeAll: true,
|
MasqueradeAll: true,
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
|
||||||
},
|
},
|
||||||
msg: "must be greater than or equal to 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPTablesConfiguration.MinSyncPeriod"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than or equal to 0")},
|
||||||
},
|
},
|
||||||
{
|
"MasqueradeBit cannot be < 0": {
|
||||||
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||||
MasqueradeBit: &invalid,
|
MasqueradeBit: pointer.Int32Ptr(-10),
|
||||||
MasqueradeAll: true,
|
MasqueradeAll: true,
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||||
},
|
},
|
||||||
msg: "must be within the range [0, 31]",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPTablesConfiguration.MasqueradeBit"), -10, "must be within the range [0, 31]")},
|
||||||
},
|
},
|
||||||
// SyncPeriod must be >= MinSyncPeriod
|
"SyncPeriod must be >= MinSyncPeriod": {
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
||||||
MasqueradeBit: &valid,
|
MasqueradeBit: pointer.Int32Ptr(5),
|
||||||
MasqueradeAll: true,
|
MasqueradeAll: true,
|
||||||
SyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
msg: fmt.Sprintf("must be greater than or equal to %s", newPath.Child("KubeProxyIPTablesConfiguration").Child("MinSyncPeriod").String()),
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPTablesConfiguration.SyncPeriod"), metav1.Duration{Duration: 5 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPTablesConfiguration.MinSyncPeriod")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, errorCase := range errorCases {
|
for _, testCase := range testCases {
|
||||||
if errs := validateKubeProxyIPTablesConfiguration(errorCase.config, newPath.Child("KubeProxyIPTablesConfiguration")); len(errs) == 0 {
|
errs := validateKubeProxyIPTablesConfiguration(testCase.config, newPath.Child("KubeIPTablesConfiguration"))
|
||||||
t.Errorf("expected failure for %s", errorCase.msg)
|
if len(testCase.expectedErrs) != len(errs) {
|
||||||
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
t.Fatalf("Expected %d errors, got %d errors: %v", len(testCase.expectedErrs), len(errs), errs)
|
||||||
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
}
|
||||||
|
for i, err := range errs {
|
||||||
|
if err.Error() != testCase.expectedErrs[i].Error() {
|
||||||
|
t.Errorf("Expected error: %s, got %s", testCase.expectedErrs[i], err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateKubeProxyIPVSConfiguration(t *testing.T) {
|
func TestValidateKubeProxyIPVSConfiguration(t *testing.T) {
|
||||||
newPath := field.NewPath("KubeProxyConfiguration")
|
newPath := field.NewPath("KubeProxyConfiguration")
|
||||||
testCases := []struct {
|
testCases := map[string]struct {
|
||||||
config kubeproxyconfig.KubeProxyIPVSConfiguration
|
config kubeproxyconfig.KubeProxyIPVSConfiguration
|
||||||
expectErr bool
|
expectedErrs field.ErrorList
|
||||||
reason string
|
|
||||||
}{
|
}{
|
||||||
{
|
"SyncPeriod is not greater than 0": {
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: -5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: -5 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: true,
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: -5 * time.Second}, "must be greater than 0"),
|
||||||
reason: "SyncPeriod must be greater than 0",
|
field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 2 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPVSConfiguration.MinSyncPeriod")},
|
||||||
},
|
},
|
||||||
{
|
"SyncPeriod cannot be 0": {
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 0 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 0 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: true,
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 0}, "must be greater than 0"),
|
||||||
reason: "SyncPeriod must be greater than 0",
|
field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 10 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPVSConfiguration.MinSyncPeriod")},
|
||||||
},
|
},
|
||||||
{
|
"MinSyncPeriod cannot be less than 0": {
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: true,
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.MinSyncPeriod"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than or equal to 0")},
|
||||||
reason: "MinSyncPeriod must be greater than or equal to 0",
|
|
||||||
},
|
},
|
||||||
{
|
"SyncPeriod must be greater than MinSyncPeriod": {
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: true,
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 5 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPVSConfiguration.MinSyncPeriod")},
|
||||||
reason: "SyncPeriod must be greater than or equal to MinSyncPeriod",
|
|
||||||
},
|
},
|
||||||
// SyncPeriod == MinSyncPeriod
|
"SyncPeriod == MinSyncPeriod": {
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: false,
|
expectedErrs: field.ErrorList{},
|
||||||
},
|
},
|
||||||
// SyncPeriod > MinSyncPeriod
|
"SyncPeriod should be > MinSyncPeriod": {
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: false,
|
expectedErrs: field.ErrorList{},
|
||||||
},
|
},
|
||||||
// SyncPeriod can be 0
|
"MinSyncPeriod can be 0": {
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
MinSyncPeriod: metav1.Duration{Duration: 0 * time.Second},
|
MinSyncPeriod: metav1.Duration{Duration: 0 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: false,
|
expectedErrs: field.ErrorList{},
|
||||||
},
|
},
|
||||||
// IPVS Timeout can be 0
|
"IPVS Timeout can be 0": {
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
TCPTimeout: metav1.Duration{Duration: 0 * time.Second},
|
TCPTimeout: metav1.Duration{Duration: 0 * time.Second},
|
||||||
TCPFinTimeout: metav1.Duration{Duration: 0 * time.Second},
|
TCPFinTimeout: metav1.Duration{Duration: 0 * time.Second},
|
||||||
UDPTimeout: metav1.Duration{Duration: 0 * time.Second},
|
UDPTimeout: metav1.Duration{Duration: 0 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: false,
|
expectedErrs: field.ErrorList{},
|
||||||
},
|
},
|
||||||
// IPVS Timeout > 0
|
"IPVS Timeout > 0": {
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
TCPTimeout: metav1.Duration{Duration: 1 * time.Second},
|
TCPTimeout: metav1.Duration{Duration: 1 * time.Second},
|
||||||
TCPFinTimeout: metav1.Duration{Duration: 2 * time.Second},
|
TCPFinTimeout: metav1.Duration{Duration: 2 * time.Second},
|
||||||
UDPTimeout: metav1.Duration{Duration: 3 * time.Second},
|
UDPTimeout: metav1.Duration{Duration: 3 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: false,
|
expectedErrs: field.ErrorList{},
|
||||||
},
|
},
|
||||||
// TCPTimeout Timeout < 0
|
"TCP,TCPFin,UDP Timeouts < 0": {
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||||
TCPTimeout: metav1.Duration{Duration: -1 * time.Second},
|
TCPTimeout: metav1.Duration{Duration: -1 * time.Second},
|
||||||
},
|
UDPTimeout: metav1.Duration{Duration: -1 * time.Second},
|
||||||
expectErr: true,
|
|
||||||
reason: "TCPTimeout must be greater than or equal to 0",
|
|
||||||
},
|
|
||||||
// TCPFinTimeout Timeout < 0
|
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
||||||
TCPFinTimeout: metav1.Duration{Duration: -1 * time.Second},
|
TCPFinTimeout: metav1.Duration{Duration: -1 * time.Second},
|
||||||
},
|
},
|
||||||
expectErr: true,
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.TCPTimeout"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than or equal to 0"),
|
||||||
reason: "TCPFinTimeout must be greater than or equal to 0",
|
field.Invalid(newPath.Child("KubeIPVSConfiguration.TCPFinTimeout"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than or equal to 0"),
|
||||||
},
|
field.Invalid(newPath.Child("KubeIPVSConfiguration.UDPTimeout"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than or equal to 0")},
|
||||||
// UDPTimeout Timeout < 0
|
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
||||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
||||||
UDPTimeout: metav1.Duration{Duration: -1 * time.Second},
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
reason: "UDPTimeout must be greater than or equal to 0",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
for _, testCase := range testCases {
|
||||||
for _, test := range testCases {
|
errs := validateKubeProxyIPVSConfiguration(testCase.config, newPath.Child("KubeIPVSConfiguration"))
|
||||||
errs := validateKubeProxyIPVSConfiguration(test.config, newPath.Child("KubeProxyIPVSConfiguration"))
|
if len(testCase.expectedErrs) != len(errs) {
|
||||||
if len(errs) == 0 && test.expectErr {
|
t.Fatalf("Expected %d errors, got %d errors: %v", len(testCase.expectedErrs), len(errs), errs)
|
||||||
t.Errorf("Expect error, got nil, reason: %s", test.reason)
|
}
|
||||||
|
for i, err := range errs {
|
||||||
|
if err.Error() != testCase.expectedErrs[i].Error() {
|
||||||
|
t.Errorf("Expected error: %s, got %s", testCase.expectedErrs[i], err.Error())
|
||||||
}
|
}
|
||||||
if len(errs) > 0 && !test.expectErr {
|
|
||||||
t.Errorf("Unexpected error: %v", errs)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateKubeProxyConntrackConfiguration(t *testing.T) {
|
func TestValidateKubeProxyConntrackConfiguration(t *testing.T) {
|
||||||
successCases := []kubeproxyconfig.KubeProxyConntrackConfiguration{
|
newPath := field.NewPath("KubeProxyConfiguration")
|
||||||
{
|
testCases := map[string]struct {
|
||||||
|
config kubeproxyconfig.KubeProxyConntrackConfiguration
|
||||||
|
expectedErrs field.ErrorList
|
||||||
|
}{
|
||||||
|
"valid 5 second timeouts": {
|
||||||
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||||
MaxPerCore: pointer.Int32Ptr(1),
|
MaxPerCore: pointer.Int32Ptr(1),
|
||||||
Min: pointer.Int32Ptr(1),
|
Min: pointer.Int32Ptr(1),
|
||||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
{
|
expectedErrs: field.ErrorList{},
|
||||||
MaxPerCore: pointer.Int32Ptr(0),
|
},
|
||||||
Min: pointer.Int32Ptr(0),
|
"valid duration equal to 0 second timeout": {
|
||||||
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||||
|
MaxPerCore: pointer.Int32Ptr(1),
|
||||||
|
Min: pointer.Int32Ptr(1),
|
||||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
||||||
},
|
},
|
||||||
}
|
expectedErrs: field.ErrorList{},
|
||||||
newPath := field.NewPath("KubeProxyConfiguration")
|
},
|
||||||
for _, successCase := range successCases {
|
"invalid MaxPerCore < 0": {
|
||||||
if errs := validateKubeProxyConntrackConfiguration(successCase, newPath.Child("KubeProxyConntrackConfiguration")); len(errs) != 0 {
|
|
||||||
t.Errorf("expected success: %v", errs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errorCases := []struct {
|
|
||||||
config kubeproxyconfig.KubeProxyConntrackConfiguration
|
|
||||||
msg string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||||
MaxPerCore: pointer.Int32Ptr(-1),
|
MaxPerCore: pointer.Int32Ptr(-1),
|
||||||
Min: pointer.Int32Ptr(1),
|
Min: pointer.Int32Ptr(1),
|
||||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
msg: "must be greater than or equal to 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeConntrackConfiguration.MaxPerCore"), -1, "must be greater than or equal to 0")},
|
||||||
},
|
},
|
||||||
{
|
"invalid minimum < 0": {
|
||||||
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||||
MaxPerCore: pointer.Int32Ptr(1),
|
MaxPerCore: pointer.Int32Ptr(1),
|
||||||
Min: pointer.Int32Ptr(-1),
|
Min: pointer.Int32Ptr(-1),
|
||||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
msg: "must be greater than or equal to 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeConntrackConfiguration.Min"), -1, "must be greater than or equal to 0")},
|
||||||
},
|
},
|
||||||
{
|
"invalid EstablishedTimeout < 0": {
|
||||||
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||||
MaxPerCore: pointer.Int32Ptr(1),
|
MaxPerCore: pointer.Int32Ptr(1),
|
||||||
Min: pointer.Int32Ptr(3),
|
Min: pointer.Int32Ptr(1),
|
||||||
TCPEstablishedTimeout: &metav1.Duration{Duration: -5 * time.Second},
|
TCPEstablishedTimeout: &metav1.Duration{Duration: -5 * time.Second},
|
||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
},
|
},
|
||||||
msg: "must be greater than or equal to 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeConntrackConfiguration.TCPEstablishedTimeout"), metav1.Duration{Duration: -5 * time.Second}, "must be greater than or equal to 0")},
|
||||||
},
|
},
|
||||||
{
|
"invalid CloseWaitTimeout < 0": {
|
||||||
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
||||||
MaxPerCore: pointer.Int32Ptr(1),
|
MaxPerCore: pointer.Int32Ptr(1),
|
||||||
Min: pointer.Int32Ptr(3),
|
Min: pointer.Int32Ptr(1),
|
||||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: -5 * time.Second},
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: -5 * time.Second},
|
||||||
},
|
},
|
||||||
msg: "must be greater than or equal to 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeConntrackConfiguration.TCPCloseWaitTimeout"), metav1.Duration{Duration: -5 * time.Second}, "must be greater than or equal to 0")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, errorCase := range errorCases {
|
for _, testCase := range testCases {
|
||||||
if errs := validateKubeProxyConntrackConfiguration(errorCase.config, newPath.Child("KubeProxyConntrackConfiguration")); len(errs) == 0 {
|
errs := validateKubeProxyConntrackConfiguration(testCase.config, newPath.Child("KubeConntrackConfiguration"))
|
||||||
t.Errorf("expected failure for %s", errorCase.msg)
|
if len(testCase.expectedErrs) != len(errs) {
|
||||||
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
t.Fatalf("Expected %d errors, got %d errors: %v", len(testCase.expectedErrs), len(errs), errs)
|
||||||
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
}
|
||||||
|
for i, err := range errs {
|
||||||
|
if err.Error() != testCase.expectedErrs[i].Error() {
|
||||||
|
t.Errorf("Expected error: %s, got %s", testCase.expectedErrs[i], err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateProxyMode(t *testing.T) {
|
func TestValidateProxyMode(t *testing.T) {
|
||||||
newPath := field.NewPath("KubeProxyConfiguration")
|
newPath := field.NewPath("KubeProxyConfiguration")
|
||||||
successCases := []kubeproxyconfig.ProxyMode{
|
successCases := []kubeproxyconfig.ProxyMode{""}
|
||||||
kubeproxyconfig.ProxyModeUserspace,
|
|
||||||
kubeproxyconfig.ProxyMode(""),
|
|
||||||
}
|
|
||||||
|
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
successCases = append(successCases, kubeproxyconfig.ProxyModeKernelspace)
|
successCases = append(successCases, kubeproxyconfig.ProxyModeKernelspace)
|
||||||
@ -774,21 +699,32 @@ func TestValidateProxyMode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorCases := []struct {
|
testCases := map[string]struct {
|
||||||
mode kubeproxyconfig.ProxyMode
|
mode kubeproxyconfig.ProxyMode
|
||||||
msg string
|
expectedErrs field.ErrorList
|
||||||
}{
|
}{
|
||||||
{
|
"valid Userspace mode": {
|
||||||
|
mode: kubeproxyconfig.ProxyModeUserspace,
|
||||||
|
expectedErrs: field.ErrorList{},
|
||||||
|
},
|
||||||
|
"blank mode should default": {
|
||||||
|
mode: kubeproxyconfig.ProxyMode(""),
|
||||||
|
expectedErrs: field.ErrorList{},
|
||||||
|
},
|
||||||
|
"invalid mode non-existent": {
|
||||||
mode: kubeproxyconfig.ProxyMode("non-existing"),
|
mode: kubeproxyconfig.ProxyMode("non-existing"),
|
||||||
msg: "or blank (blank means the",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ProxyMode"), "non-existing", "must be iptables,ipvs,userspace or blank (blank means the best-available proxy [currently iptables])")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
for _, testCase := range testCases {
|
||||||
for _, errorCase := range errorCases {
|
errs := validateProxyMode(testCase.mode, newPath)
|
||||||
if errs := validateProxyMode(errorCase.mode, newPath.Child("ProxyMode")); len(errs) == 0 {
|
if len(testCase.expectedErrs) != len(errs) {
|
||||||
t.Errorf("expected failure %s for %v", errorCase.msg, errorCase.mode)
|
t.Fatalf("Expected %d errors, got %d errors: %v", len(testCase.expectedErrs), len(errs), errs)
|
||||||
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
}
|
||||||
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
for i, err := range errs {
|
||||||
|
if err.Error() != testCase.expectedErrs[i].Error() {
|
||||||
|
t.Errorf("Expected error: %s, got %v", testCase.expectedErrs[i], err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -796,36 +732,33 @@ func TestValidateProxyMode(t *testing.T) {
|
|||||||
func TestValidateClientConnectionConfiguration(t *testing.T) {
|
func TestValidateClientConnectionConfiguration(t *testing.T) {
|
||||||
newPath := field.NewPath("KubeProxyConfiguration")
|
newPath := field.NewPath("KubeProxyConfiguration")
|
||||||
|
|
||||||
successCases := []componentbaseconfig.ClientConnectionConfiguration{
|
testCases := map[string]struct {
|
||||||
{
|
|
||||||
Burst: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Burst: 5,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, successCase := range successCases {
|
|
||||||
if errs := validateClientConnectionConfiguration(successCase, newPath.Child("Burst")); len(errs) != 0 {
|
|
||||||
t.Errorf("expected success: %v", errs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errorCases := []struct {
|
|
||||||
ccc componentbaseconfig.ClientConnectionConfiguration
|
ccc componentbaseconfig.ClientConnectionConfiguration
|
||||||
msg string
|
expectedErrs field.ErrorList
|
||||||
}{
|
}{
|
||||||
{
|
"successful 0 value": {
|
||||||
|
ccc: componentbaseconfig.ClientConnectionConfiguration{Burst: 0},
|
||||||
|
expectedErrs: field.ErrorList{},
|
||||||
|
},
|
||||||
|
"successful 5 value": {
|
||||||
|
ccc: componentbaseconfig.ClientConnectionConfiguration{Burst: 5},
|
||||||
|
expectedErrs: field.ErrorList{},
|
||||||
|
},
|
||||||
|
"burst < 0": {
|
||||||
ccc: componentbaseconfig.ClientConnectionConfiguration{Burst: -5},
|
ccc: componentbaseconfig.ClientConnectionConfiguration{Burst: -5},
|
||||||
msg: "must be greater than or equal to 0",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("Burst"), -5, "must be greater than or equal to 0")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, errorCase := range errorCases {
|
for _, testCase := range testCases {
|
||||||
if errs := validateClientConnectionConfiguration(errorCase.ccc, newPath.Child("Burst")); len(errs) == 0 {
|
errs := validateClientConnectionConfiguration(testCase.ccc, newPath)
|
||||||
t.Errorf("expected failure for %s", errorCase.msg)
|
if len(testCase.expectedErrs) != len(errs) {
|
||||||
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
t.Fatalf("Expected %d errors, got %d errors: %v", len(testCase.expectedErrs), len(errs), errs)
|
||||||
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
}
|
||||||
|
for i, err := range errs {
|
||||||
|
if err.Error() != testCase.expectedErrs[i].Error() {
|
||||||
|
t.Errorf("Expected error: %s, got %s", testCase.expectedErrs[i], err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -845,37 +778,41 @@ func TestValidateHostPort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorCases := []struct {
|
errorCases := map[string]struct {
|
||||||
ccc string
|
ip string
|
||||||
msg string
|
expectedErrs field.ErrorList
|
||||||
}{
|
}{
|
||||||
{
|
"missing port": {
|
||||||
ccc: "10.10.10.10",
|
ip: "10.10.10.10",
|
||||||
msg: "must be IP:port",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("HealthzBindAddress"), "10.10.10.10", "must be IP:port")},
|
||||||
},
|
},
|
||||||
{
|
"digits outside of 1-255": {
|
||||||
ccc: "123.456.789.10:12345",
|
ip: "123.456.789.10:12345",
|
||||||
msg: "must be a valid IP",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("HealthzBindAddress"), "123.456.789.10", "must be a valid IP")},
|
||||||
},
|
},
|
||||||
{
|
"invalid named-port": {
|
||||||
ccc: "10.10.10.10:foo",
|
ip: "10.10.10.10:foo",
|
||||||
msg: "must be a valid port",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("HealthzBindAddress"), "foo", "must be a valid port")},
|
||||||
},
|
},
|
||||||
{
|
"port cannot be 0": {
|
||||||
ccc: "10.10.10.10:0",
|
ip: "10.10.10.10:0",
|
||||||
msg: "must be a valid port",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("HealthzBindAddress"), "0", "must be a valid port")},
|
||||||
},
|
},
|
||||||
{
|
"port is greater than allowed range": {
|
||||||
ccc: "10.10.10.10:65536",
|
ip: "10.10.10.10:65536",
|
||||||
msg: "must be a valid port",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("HealthzBindAddress"), "65536", "must be a valid port")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, errorCase := range errorCases {
|
for _, errorCase := range errorCases {
|
||||||
if errs := validateHostPort(errorCase.ccc, newPath.Child("HealthzBindAddress")); len(errs) == 0 {
|
errs := validateHostPort(errorCase.ip, newPath.Child("HealthzBindAddress"))
|
||||||
t.Errorf("expected failure for %s", errorCase.msg)
|
if len(errorCase.expectedErrs) != len(errs) {
|
||||||
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
t.Fatalf("Expected %d errors, got %d errors: %v", len(errorCase.expectedErrs), len(errs), errs)
|
||||||
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
}
|
||||||
|
for i, err := range errs {
|
||||||
|
if err.Error() != errorCase.expectedErrs[i].Error() {
|
||||||
|
t.Errorf("Expected error: %s, got %s", errorCase.expectedErrs[i], err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -903,21 +840,25 @@ func TestValidateIPVSSchedulerMethod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorCases := []struct {
|
errorCases := map[string]struct {
|
||||||
mode kubeproxyconfig.IPVSSchedulerMethod
|
mode kubeproxyconfig.IPVSSchedulerMethod
|
||||||
msg string
|
expectedErrs field.ErrorList
|
||||||
}{
|
}{
|
||||||
{
|
"non-existent scheduler method": {
|
||||||
mode: kubeproxyconfig.IPVSSchedulerMethod("non-existing"),
|
mode: kubeproxyconfig.IPVSSchedulerMethod("non-existing"),
|
||||||
msg: "blank means the default algorithm method (currently rr)",
|
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ProxyMode.Scheduler"), "non-existing", "must be in [rr wrr lc wlc lblc lblcr sh dh sed nq ], blank means the default algorithm method (currently rr)")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, errorCase := range errorCases {
|
for _, errorCase := range errorCases {
|
||||||
if errs := validateIPVSSchedulerMethod(errorCase.mode, newPath.Child("ProxyMode")); len(errs) == 0 {
|
errs := validateIPVSSchedulerMethod(errorCase.mode, newPath.Child("ProxyMode"))
|
||||||
t.Errorf("expected failure for %s", errorCase.msg)
|
if len(errorCase.expectedErrs) != len(errs) {
|
||||||
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
t.Fatalf("Expected %d errors, got %d errors: %v", len(errorCase.expectedErrs), len(errs), errs)
|
||||||
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
}
|
||||||
|
for i, err := range errs {
|
||||||
|
if err.Error() != errorCase.expectedErrs[i].Error() {
|
||||||
|
t.Fatalf("Expected error: %s, got %s", errorCase.expectedErrs[i], err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user