mirror of https://github.com/k3s-io/k3s
Merge pull request #49087 from allencloud/validate-kube-proxy-configs
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. validate kube-proxy options Signed-off-by: allencloud <allen.sun@daocloud.io> **What this PR does / why we need it**: I found that some components does not validate the config at the startup of itself. Without this, startup will bring some bad things. And I think fail fast can save customer's time and make thing simple and clear. This PR add validation of kube-proxy's configuration. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # fixes https://github.com/kubernetes/kubernetes/issues/53578 **Special notes for your reviewer**: Actually I only add a file named validation.go in `pkg/apis/componentconfig/validation/`, while I see in every folder, there is a file named `BUILD`, I hope to know how to add this file. **Release note**: ```release-note NONE ```pull/6/head
commit
ee80933d34
|
@ -12,6 +12,7 @@ go_library(
|
|||
"conntrack.go",
|
||||
"server.go",
|
||||
"server_others.go",
|
||||
"validation.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"server_windows.go",
|
||||
|
@ -20,6 +21,7 @@ go_library(
|
|||
}),
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/validation:go_default_library",
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/apis/componentconfig/v1alpha1:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
|
@ -58,6 +60,7 @@ go_library(
|
|||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
|
@ -79,7 +82,10 @@ go_library(
|
|||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["server_test.go"],
|
||||
srcs = [
|
||||
"server_test.go",
|
||||
"validation_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
|
@ -92,6 +98,7 @@ go_test(
|
|||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -203,6 +203,10 @@ func (o *Options) Validate(args []string) error {
|
|||
return errors.New("no arguments are supported")
|
||||
}
|
||||
|
||||
if errs := Validate(o.config); len(errs) != 0 {
|
||||
return errs.ToAggregate()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
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 app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
)
|
||||
|
||||
// Validate validates the configuration of kube-proxy
|
||||
func Validate(config *componentconfig.KubeProxyConfiguration) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
newPath := field.NewPath("KubeProxyConfiguration")
|
||||
|
||||
allErrs = append(allErrs, validateKubeProxyIPTablesConfiguration(config.IPTables, newPath.Child("KubeProxyIPTablesConfiguration"))...)
|
||||
allErrs = append(allErrs, validateKubeProxyConntrackConfiguration(config.Conntrack, newPath.Child("KubeProxyConntrackConfiguration"))...)
|
||||
allErrs = append(allErrs, validateProxyMode(config.Mode, newPath.Child("Mode"))...)
|
||||
allErrs = append(allErrs, validateClientConnectionConfiguration(config.ClientConnection, newPath.Child("ClientConnection"))...)
|
||||
|
||||
if config.OOMScoreAdj != nil && (*config.OOMScoreAdj < -1000 || *config.OOMScoreAdj > 1000) {
|
||||
allErrs = append(allErrs, field.Invalid(newPath.Child("OOMScoreAdj"), *config.OOMScoreAdj, "must be within the range [-1000, 1000]"))
|
||||
}
|
||||
|
||||
if config.UDPIdleTimeout.Duration <= 0 {
|
||||
allErrs = append(allErrs, field.Invalid(newPath.Child("UDPIdleTimeout"), config.UDPIdleTimeout, "must be greater than 0"))
|
||||
}
|
||||
|
||||
if config.ConfigSyncPeriod.Duration <= 0 {
|
||||
allErrs = append(allErrs, field.Invalid(newPath.Child("ConfigSyncPeriod"), config.ConfigSyncPeriod, "must be greater than 0"))
|
||||
}
|
||||
|
||||
if net.ParseIP(config.BindAddress) == nil {
|
||||
allErrs = append(allErrs, field.Invalid(newPath.Child("BindAddress"), config.BindAddress, "not a valid textual representation of an IP address"))
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateHostPort(config.HealthzBindAddress, newPath.Child("HealthzBindAddress"))...)
|
||||
allErrs = append(allErrs, validateHostPort(config.MetricsBindAddress, newPath.Child("MetricsBindAddress"))...)
|
||||
|
||||
if _, _, err := net.ParseCIDR(config.ClusterCIDR); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(newPath.Child("ClusterCIDR"), config.ClusterCIDR, "must be a valid CIDR block (e.g. 10.100.0.0/16)"))
|
||||
}
|
||||
|
||||
if _, err := utilnet.ParsePortRange(config.PortRange); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(newPath.Child("PortRange"), config.PortRange, "must be a valid port range (e.g. 300-2000)"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKubeProxyIPTablesConfiguration(config componentconfig.KubeProxyIPTablesConfiguration, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if config.MasqueradeBit != nil && (*config.MasqueradeBit < 0 || *config.MasqueradeBit > 31) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("MasqueradeBit"), config.MasqueradeBit, "must be within the range [0, 31]"))
|
||||
}
|
||||
|
||||
if config.SyncPeriod.Duration <= 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("SyncPeriod"), config.SyncPeriod, "must be greater than 0"))
|
||||
}
|
||||
|
||||
if config.MinSyncPeriod.Duration < 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("MinSyncPeriod"), config.MinSyncPeriod, "must be greater than or equal to 0"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKubeProxyConntrackConfiguration(config componentconfig.KubeProxyConntrackConfiguration, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if config.Max < 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("Max"), config.Max, "must be greater than or equal to 0"))
|
||||
}
|
||||
|
||||
if config.MaxPerCore < 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("MaxPerCore"), config.MaxPerCore, "must be greater than or equal to 0"))
|
||||
}
|
||||
|
||||
if config.Min < 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("Min"), config.Min, "must be greater than or equal to 0"))
|
||||
}
|
||||
|
||||
if config.TCPEstablishedTimeout.Duration <= 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("TCPEstablishedTimeout"), config.TCPEstablishedTimeout, "must be greater than 0"))
|
||||
}
|
||||
|
||||
if config.TCPCloseWaitTimeout.Duration <= 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("TCPCloseWaitTimeout"), config.TCPCloseWaitTimeout, "must be greater than 0"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateProxyMode(mode componentconfig.ProxyMode, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
switch mode {
|
||||
case componentconfig.ProxyModeUserspace:
|
||||
case componentconfig.ProxyModeIPTables:
|
||||
case "":
|
||||
default:
|
||||
modes := []string{string(componentconfig.ProxyModeUserspace), string(componentconfig.ProxyModeIPTables)}
|
||||
errMsg := fmt.Sprintf("must be %s or blank (blank means the best-available proxy (currently iptables)", strings.Join(modes, ","))
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateClientConnectionConfiguration(config componentconfig.ClientConnectionConfiguration, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(config.Burst), fldPath.Child("Burst"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateHostPort(input string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
hostIP, port, err := net.SplitHostPort(input)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, input, "must be IP:port"))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(hostIP); ip == nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, hostIP, "must be a valid IP"))
|
||||
}
|
||||
|
||||
if p, err := strconv.Atoi(port); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, port, "must be a valid port"))
|
||||
} else if p < 1 || p > 65535 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, port, "must be a valid port"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
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 app
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
)
|
||||
|
||||
func TestValidateKubeProxyConfiguration(t *testing.T) {
|
||||
successCases := []componentconfig.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: componentconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(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 componentconfig.KubeProxyConfiguration
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
config: componentconfig.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: componentconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(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: componentconfig.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: componentconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(1),
|
||||
TCPEstablishedTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
},
|
||||
msg: "must be IP:port",
|
||||
},
|
||||
{
|
||||
config: componentconfig.KubeProxyConfiguration{
|
||||
BindAddress: "10.10.12.11",
|
||||
HealthzBindAddress: "0.0.0.0:12345",
|
||||
// only HealthzBindAddress 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: componentconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(1),
|
||||
TCPEstablishedTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
},
|
||||
msg: "must be IP:port",
|
||||
},
|
||||
{
|
||||
config: componentconfig.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: componentconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(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: componentconfig.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: componentconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(1),
|
||||
TCPEstablishedTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
},
|
||||
msg: "must be greater than 0",
|
||||
},
|
||||
{
|
||||
config: componentconfig.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: componentconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
Conntrack: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(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 := []componentconfig.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 componentconfig.KubeProxyIPTablesConfiguration
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
config: componentconfig.KubeProxyIPTablesConfiguration{
|
||||
MasqueradeAll: true,
|
||||
SyncPeriod: metav1.Duration{Duration: -5 * time.Second},
|
||||
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||
},
|
||||
msg: "must be greater than 0",
|
||||
},
|
||||
{
|
||||
config: componentconfig.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: componentconfig.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]",
|
||||
},
|
||||
}
|
||||
|
||||
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 TestValidateKubeProxyConntrackConfiguration(t *testing.T) {
|
||||
successCases := []componentconfig.KubeProxyConntrackConfiguration{
|
||||
{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(1),
|
||||
TCPEstablishedTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
{
|
||||
Max: 0,
|
||||
MaxPerCore: 0,
|
||||
Min: 0,
|
||||
TCPEstablishedTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
TCPCloseWaitTimeout: metav1.Duration{Duration: 60 * 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 componentconfig.KubeProxyConntrackConfiguration
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
config: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(-1),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(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: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(-1),
|
||||
Min: int32(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: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(2),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(-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: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(4),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(3),
|
||||
TCPEstablishedTimeout: metav1.Duration{Duration: -5 * time.Second},
|
||||
TCPCloseWaitTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
msg: "must be greater than 0",
|
||||
},
|
||||
{
|
||||
config: componentconfig.KubeProxyConntrackConfiguration{
|
||||
Max: int32(4),
|
||||
MaxPerCore: int32(1),
|
||||
Min: int32(3),
|
||||
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 := 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 := []componentconfig.ProxyMode{
|
||||
componentconfig.ProxyModeUserspace,
|
||||
componentconfig.ProxyModeIPTables,
|
||||
componentconfig.ProxyMode(""),
|
||||
}
|
||||
|
||||
for _, successCase := range successCases {
|
||||
if errs := validateProxyMode(successCase, newPath.Child("ProxyMode")); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
errorCases := []struct {
|
||||
mode componentconfig.ProxyMode
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
mode: componentconfig.ProxyMode("non-existing"),
|
||||
msg: "or blank (blank means the best-available proxy (currently iptables)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, errorCase := range errorCases {
|
||||
if errs := validateProxyMode(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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,7 +46,6 @@ filegroup(
|
|||
"//pkg/apis/componentconfig/fuzzer:all-srcs",
|
||||
"//pkg/apis/componentconfig/install:all-srcs",
|
||||
"//pkg/apis/componentconfig/v1alpha1:all-srcs",
|
||||
"//pkg/apis/componentconfig/validation:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["validation.go"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
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
|
Loading…
Reference in New Issue