mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 09:49:50 +00:00
proxy: Restructure config validation tests to check errors
The tests for most functions have also been revised to check the errors explicitly upon validating. This will properly catch occasions where we should be returning multiple errors if more error occurs or if just one block is failing. Signed-off-by: Christopher M. Luciano <cmluciano@us.ibm.com>
This commit is contained in:
parent
a439bc5572
commit
a036577e2c
@ -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