mirror of https://github.com/k3s-io/k3s
845 lines
28 KiB
Go
845 lines
28 KiB
Go
/*
|
|
Copyright 2017 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package validation
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
apimachineryconfig "k8s.io/apimachinery/pkg/apis/config"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
|
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
|
|
"k8s.io/utils/pointer"
|
|
)
|
|
|
|
func TestValidateKubeProxyConfiguration(t *testing.T) {
|
|
var proxyMode kubeproxyconfig.ProxyMode
|
|
if runtime.GOOS == "windows" {
|
|
proxyMode = kubeproxyconfig.ProxyModeKernelspace
|
|
} else {
|
|
proxyMode = kubeproxyconfig.ProxyModeIPVS
|
|
}
|
|
successCases := []kubeproxyconfig.KubeProxyConfiguration{
|
|
{
|
|
BindAddress: "192.168.59.103",
|
|
HealthzBindAddress: "0.0.0.0:10256",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
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},
|
|
},
|
|
Mode: proxyMode,
|
|
IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
|
Max: pointer.Int32Ptr(2),
|
|
MaxPerCore: pointer.Int32Ptr(1),
|
|
Min: pointer.Int32Ptr(1),
|
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
},
|
|
{
|
|
BindAddress: "192.168.59.103",
|
|
HealthzBindAddress: "0.0.0.0:10256",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
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{
|
|
Max: pointer.Int32Ptr(2),
|
|
MaxPerCore: pointer.Int32Ptr(1),
|
|
Min: pointer.Int32Ptr(1),
|
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
},
|
|
{
|
|
BindAddress: "192.168.59.103",
|
|
HealthzBindAddress: "",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
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{
|
|
Max: pointer.Int32Ptr(2),
|
|
MaxPerCore: pointer.Int32Ptr(1),
|
|
Min: pointer.Int32Ptr(1),
|
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, successCase := range successCases {
|
|
if errs := Validate(&successCase); len(errs) != 0 {
|
|
t.Errorf("expected success: %v", errs)
|
|
}
|
|
}
|
|
|
|
errorCases := []struct {
|
|
config kubeproxyconfig.KubeProxyConfiguration
|
|
msg string
|
|
}{
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
// only BindAddress is invalid
|
|
BindAddress: "10.10.12.11:2000",
|
|
HealthzBindAddress: "0.0.0.0:10256",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
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{
|
|
Max: pointer.Int32Ptr(2),
|
|
MaxPerCore: pointer.Int32Ptr(1),
|
|
Min: pointer.Int32Ptr(1),
|
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
},
|
|
msg: "not a valid textual representation of an IP address",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
BindAddress: "10.10.12.11",
|
|
// only HealthzBindAddress is invalid
|
|
HealthzBindAddress: "0.0.0.0",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
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{
|
|
Max: pointer.Int32Ptr(2),
|
|
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 IP:port",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
BindAddress: "10.10.12.11",
|
|
HealthzBindAddress: "0.0.0.0:12345",
|
|
// only MetricsBindAddress is invalid
|
|
MetricsBindAddress: "127.0.0.1",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
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{
|
|
Max: pointer.Int32Ptr(2),
|
|
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 IP:port",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
BindAddress: "10.10.12.11",
|
|
HealthzBindAddress: "0.0.0.0:12345",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
// only ClusterCIDR is invalid
|
|
ClusterCIDR: "192.168.59.0",
|
|
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{
|
|
Max: pointer.Int32Ptr(2),
|
|
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 CIDR block (e.g. 10.100.0.0/16)",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
BindAddress: "10.10.12.11",
|
|
HealthzBindAddress: "0.0.0.0:12345",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
// only UDPIdleTimeout is invalid
|
|
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{
|
|
Max: pointer.Int32Ptr(2),
|
|
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 greater than 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
BindAddress: "10.10.12.11",
|
|
HealthzBindAddress: "0.0.0.0:12345",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second},
|
|
// only ConfigSyncPeriod is invalid
|
|
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{
|
|
Max: pointer.Int32Ptr(2),
|
|
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 greater than 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConfiguration{
|
|
BindAddress: "192.168.59.103",
|
|
HealthzBindAddress: "0.0.0.0:10256",
|
|
MetricsBindAddress: "127.0.0.1:10249",
|
|
ClusterCIDR: "192.168.59.0/24",
|
|
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},
|
|
},
|
|
// not specifying valid period in IPVS mode.
|
|
Mode: kubeproxyconfig.ProxyModeIPVS,
|
|
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
|
Max: pointer.Int32Ptr(2),
|
|
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 greater than 0",
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := Validate(&errorCase.config); len(errs) == 0 {
|
|
t.Errorf("expected failure for %s", errorCase.msg)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
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")
|
|
for _, successCase := range successCases {
|
|
if errs := validateKubeProxyIPTablesConfiguration(successCase, newPath.Child("KubeProxyIPTablesConfiguration")); len(errs) != 0 {
|
|
t.Errorf("expected success: %v", errs)
|
|
}
|
|
}
|
|
|
|
invalid := int32(-10)
|
|
errorCases := []struct {
|
|
config kubeproxyconfig.KubeProxyIPTablesConfiguration
|
|
msg string
|
|
}{
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
|
MasqueradeAll: true,
|
|
SyncPeriod: metav1.Duration{Duration: -5 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
|
},
|
|
msg: "must be greater than 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
|
MasqueradeBit: &valid,
|
|
MasqueradeAll: true,
|
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
|
|
},
|
|
msg: "must be greater than or equal to 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
|
MasqueradeBit: &invalid,
|
|
MasqueradeAll: true,
|
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
|
},
|
|
msg: "must be within the range [0, 31]",
|
|
},
|
|
// SyncPeriod must be >= MinSyncPeriod
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPTablesConfiguration{
|
|
MasqueradeBit: &valid,
|
|
MasqueradeAll: true,
|
|
SyncPeriod: metav1.Duration{Duration: 1 * 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()),
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := validateKubeProxyIPTablesConfiguration(errorCase.config, newPath.Child("KubeProxyIPTablesConfiguration")); len(errs) == 0 {
|
|
t.Errorf("expected failure for %s", errorCase.msg)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateKubeProxyIPVSConfiguration(t *testing.T) {
|
|
newPath := field.NewPath("KubeProxyConfiguration")
|
|
testCases := []struct {
|
|
config kubeproxyconfig.KubeProxyIPVSConfiguration
|
|
expectErr bool
|
|
reason string
|
|
}{
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
SyncPeriod: metav1.Duration{Duration: -5 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
|
},
|
|
expectErr: true,
|
|
reason: "SyncPeriod must be greater than 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
SyncPeriod: metav1.Duration{Duration: 0 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
|
},
|
|
expectErr: true,
|
|
reason: "SyncPeriod must be greater than 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: -1 * time.Second},
|
|
},
|
|
expectErr: true,
|
|
reason: "MinSyncPeriod must be greater than or equal to 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
SyncPeriod: metav1.Duration{Duration: 1 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
expectErr: true,
|
|
reason: "SyncPeriod must be greater than or equal to MinSyncPeriod",
|
|
},
|
|
// SyncPeriod == MinSyncPeriod
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
|
},
|
|
expectErr: false,
|
|
},
|
|
// SyncPeriod > MinSyncPeriod
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
SyncPeriod: metav1.Duration{Duration: 10 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
expectErr: false,
|
|
},
|
|
// SyncPeriod can be 0
|
|
{
|
|
config: kubeproxyconfig.KubeProxyIPVSConfiguration{
|
|
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
|
MinSyncPeriod: metav1.Duration{Duration: 0 * time.Second},
|
|
},
|
|
expectErr: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
errs := validateKubeProxyIPVSConfiguration(test.config, newPath.Child("KubeProxyIPVSConfiguration"))
|
|
if len(errs) == 0 && test.expectErr {
|
|
t.Errorf("Expect error, got nil, reason: %s", test.reason)
|
|
}
|
|
if len(errs) > 0 && !test.expectErr {
|
|
t.Errorf("Unexpected error: %v", errs)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateKubeProxyConntrackConfiguration(t *testing.T) {
|
|
successCases := []kubeproxyconfig.KubeProxyConntrackConfiguration{
|
|
{
|
|
Max: pointer.Int32Ptr(2),
|
|
MaxPerCore: pointer.Int32Ptr(1),
|
|
Min: pointer.Int32Ptr(1),
|
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
{
|
|
Max: pointer.Int32Ptr(0),
|
|
MaxPerCore: pointer.Int32Ptr(0),
|
|
Min: pointer.Int32Ptr(0),
|
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
|
},
|
|
}
|
|
newPath := field.NewPath("KubeProxyConfiguration")
|
|
for _, successCase := range successCases {
|
|
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{
|
|
Max: pointer.Int32Ptr(-1),
|
|
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 greater than or equal to 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
|
Max: pointer.Int32Ptr(2),
|
|
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 greater than or equal to 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
|
Max: pointer.Int32Ptr(2),
|
|
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 greater than or equal to 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
|
Max: pointer.Int32Ptr(4),
|
|
MaxPerCore: pointer.Int32Ptr(1),
|
|
Min: pointer.Int32Ptr(3),
|
|
TCPEstablishedTimeout: &metav1.Duration{Duration: -5 * time.Second},
|
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
},
|
|
msg: "must be greater than or equal to 0",
|
|
},
|
|
{
|
|
config: kubeproxyconfig.KubeProxyConntrackConfiguration{
|
|
Max: pointer.Int32Ptr(4),
|
|
MaxPerCore: pointer.Int32Ptr(1),
|
|
Min: pointer.Int32Ptr(3),
|
|
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
|
TCPCloseWaitTimeout: &metav1.Duration{Duration: -5 * time.Second},
|
|
},
|
|
msg: "must be greater than or equal to 0",
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := validateKubeProxyConntrackConfiguration(errorCase.config, newPath.Child("KubeProxyConntrackConfiguration")); len(errs) == 0 {
|
|
t.Errorf("expected failure for %s", errorCase.msg)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateProxyMode(t *testing.T) {
|
|
newPath := field.NewPath("KubeProxyConfiguration")
|
|
successCases := []kubeproxyconfig.ProxyMode{
|
|
kubeproxyconfig.ProxyModeUserspace,
|
|
kubeproxyconfig.ProxyMode(""),
|
|
}
|
|
|
|
if runtime.GOOS == "windows" {
|
|
successCases = append(successCases, kubeproxyconfig.ProxyModeKernelspace)
|
|
} else {
|
|
successCases = append(successCases, kubeproxyconfig.ProxyModeIPTables, kubeproxyconfig.ProxyModeIPVS)
|
|
}
|
|
|
|
for _, successCase := range successCases {
|
|
if errs := validateProxyMode(successCase, newPath.Child("ProxyMode")); len(errs) != 0 {
|
|
t.Errorf("expected success: %v", errs)
|
|
}
|
|
}
|
|
|
|
errorCases := []struct {
|
|
mode kubeproxyconfig.ProxyMode
|
|
msg string
|
|
}{
|
|
{
|
|
mode: kubeproxyconfig.ProxyMode("non-existing"),
|
|
msg: "or blank (blank means the",
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := validateProxyMode(errorCase.mode, newPath.Child("ProxyMode")); len(errs) == 0 {
|
|
t.Errorf("expected failure %s for %v", errorCase.msg, errorCase.mode)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateClientConnectionConfiguration(t *testing.T) {
|
|
newPath := field.NewPath("KubeProxyConfiguration")
|
|
|
|
successCases := []apimachineryconfig.ClientConnectionConfiguration{
|
|
{
|
|
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 apimachineryconfig.ClientConnectionConfiguration
|
|
msg string
|
|
}{
|
|
{
|
|
ccc: apimachineryconfig.ClientConnectionConfiguration{Burst: -5},
|
|
msg: "must be greater than or equal to 0",
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := validateClientConnectionConfiguration(errorCase.ccc, newPath.Child("Burst")); len(errs) == 0 {
|
|
t.Errorf("expected failure for %s", errorCase.msg)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateHostPort(t *testing.T) {
|
|
newPath := field.NewPath("KubeProxyConfiguration")
|
|
|
|
successCases := []string{
|
|
"0.0.0.0:10256",
|
|
"127.0.0.1:10256",
|
|
"10.10.10.10:10256",
|
|
}
|
|
|
|
for _, successCase := range successCases {
|
|
if errs := validateHostPort(successCase, newPath.Child("HealthzBindAddress")); len(errs) != 0 {
|
|
t.Errorf("expected success: %v", errs)
|
|
}
|
|
}
|
|
|
|
errorCases := []struct {
|
|
ccc string
|
|
msg string
|
|
}{
|
|
{
|
|
ccc: "10.10.10.10",
|
|
msg: "must be IP:port",
|
|
},
|
|
{
|
|
ccc: "123.456.789.10:12345",
|
|
msg: "must be a valid IP",
|
|
},
|
|
{
|
|
ccc: "10.10.10.10:foo",
|
|
msg: "must be a valid port",
|
|
},
|
|
{
|
|
ccc: "10.10.10.10:0",
|
|
msg: "must be a valid port",
|
|
},
|
|
{
|
|
ccc: "10.10.10.10:65536",
|
|
msg: "must be a valid port",
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := validateHostPort(errorCase.ccc, newPath.Child("HealthzBindAddress")); len(errs) == 0 {
|
|
t.Errorf("expected failure for %s", errorCase.msg)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateIPVSSchedulerMethod(t *testing.T) {
|
|
newPath := field.NewPath("KubeProxyConfiguration")
|
|
|
|
successCases := []kubeproxyconfig.IPVSSchedulerMethod{
|
|
kubeproxyconfig.RoundRobin,
|
|
kubeproxyconfig.WeightedRoundRobin,
|
|
kubeproxyconfig.LeastConnection,
|
|
kubeproxyconfig.WeightedLeastConnection,
|
|
kubeproxyconfig.LocalityBasedLeastConnection,
|
|
kubeproxyconfig.LocalityBasedLeastConnectionWithReplication,
|
|
kubeproxyconfig.SourceHashing,
|
|
kubeproxyconfig.DestinationHashing,
|
|
kubeproxyconfig.ShortestExpectedDelay,
|
|
kubeproxyconfig.NeverQueue,
|
|
"",
|
|
}
|
|
|
|
for _, successCase := range successCases {
|
|
if errs := validateIPVSSchedulerMethod(successCase, newPath.Child("Scheduler")); len(errs) != 0 {
|
|
t.Errorf("expected success: %v", errs)
|
|
}
|
|
}
|
|
|
|
errorCases := []struct {
|
|
mode kubeproxyconfig.IPVSSchedulerMethod
|
|
msg string
|
|
}{
|
|
{
|
|
mode: kubeproxyconfig.IPVSSchedulerMethod("non-existing"),
|
|
msg: "blank means the default algorithm method (currently rr)",
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := validateIPVSSchedulerMethod(errorCase.mode, newPath.Child("ProxyMode")); len(errs) == 0 {
|
|
t.Errorf("expected failure for %s", errorCase.msg)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateKubeProxyNodePortAddress(t *testing.T) {
|
|
newPath := field.NewPath("KubeProxyConfiguration")
|
|
|
|
successCases := []struct {
|
|
addresses []string
|
|
}{
|
|
{[]string{}},
|
|
{[]string{"127.0.0.0/8"}},
|
|
{[]string{"0.0.0.0/0"}},
|
|
{[]string{"::/0"}},
|
|
{[]string{"127.0.0.1/32", "1.2.3.0/24"}},
|
|
{[]string{"127.0.0.0/8"}},
|
|
{[]string{"127.0.0.1/32"}},
|
|
{[]string{"::1/128"}},
|
|
{[]string{"1.2.3.4/32"}},
|
|
{[]string{"10.20.30.0/24"}},
|
|
{[]string{"10.20.0.0/16", "100.200.0.0/16"}},
|
|
{[]string{"10.0.0.0/8"}},
|
|
{[]string{"2001:db8::/32"}},
|
|
}
|
|
|
|
for _, successCase := range successCases {
|
|
if errs := validateKubeProxyNodePortAddress(successCase.addresses, newPath.Child("NodePortAddresses")); len(errs) != 0 {
|
|
t.Errorf("expected success: %v", errs)
|
|
}
|
|
}
|
|
|
|
errorCases := []struct {
|
|
addresses []string
|
|
msg string
|
|
}{
|
|
{
|
|
addresses: []string{"foo"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"1.2.3"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{""},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"10.20.30.40"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"::1"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"2001:db8:1"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"2001:db8:xyz/64"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := validateKubeProxyNodePortAddress(errorCase.addresses, newPath.Child("NodePortAddresses")); len(errs) == 0 {
|
|
t.Errorf("expected failure for %s", errorCase.msg)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateKubeProxyExcludeCIDRs(t *testing.T) {
|
|
// TODO(rramkumar): This test is a copy of TestValidateKubeProxyNodePortAddress.
|
|
// Maybe some code can be shared?
|
|
newPath := field.NewPath("KubeProxyConfiguration")
|
|
|
|
successCases := []struct {
|
|
addresses []string
|
|
}{
|
|
{[]string{}},
|
|
{[]string{"127.0.0.0/8"}},
|
|
{[]string{"0.0.0.0/0"}},
|
|
{[]string{"::/0"}},
|
|
{[]string{"127.0.0.1/32", "1.2.3.0/24"}},
|
|
{[]string{"127.0.0.0/8"}},
|
|
{[]string{"127.0.0.1/32"}},
|
|
{[]string{"::1/128"}},
|
|
{[]string{"1.2.3.4/32"}},
|
|
{[]string{"10.20.30.0/24"}},
|
|
{[]string{"10.20.0.0/16", "100.200.0.0/16"}},
|
|
{[]string{"10.0.0.0/8"}},
|
|
{[]string{"2001:db8::/32"}},
|
|
}
|
|
|
|
for _, successCase := range successCases {
|
|
if errs := validateIPVSExcludeCIDRs(successCase.addresses, newPath.Child("ExcludeCIDRs")); len(errs) != 0 {
|
|
t.Errorf("expected success: %v", errs)
|
|
}
|
|
}
|
|
|
|
errorCases := []struct {
|
|
addresses []string
|
|
msg string
|
|
}{
|
|
{
|
|
addresses: []string{"foo"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"1.2.3"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{""},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"10.20.30.40"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"::1"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"2001:db8:1"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
{
|
|
addresses: []string{"2001:db8:xyz/64"},
|
|
msg: "must be a valid IP block",
|
|
},
|
|
}
|
|
|
|
for _, errorCase := range errorCases {
|
|
if errs := validateIPVSExcludeCIDRs(errorCase.addresses, newPath.Child("ExcludeCIDRs")); len(errs) == 0 {
|
|
t.Errorf("expected failure for %s", errorCase.msg)
|
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
|
}
|
|
}
|
|
}
|