diff --git a/cmd/kube-proxy/app/validation.go b/cmd/kube-proxy/app/validation.go index 3eead9da06b..79dc7011940 100644 --- a/cmd/kube-proxy/app/validation.go +++ b/cmd/kube-proxy/app/validation.go @@ -38,7 +38,7 @@ func Validate(config *componentconfig.KubeProxyConfiguration) field.ErrorList { 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"))...) - allErrs = append(allErrs, validateIPVSSchedulerMethod(config.IPVS.Scheduler, newPath.Child("KubeProxyIPVSConfiguration").Child("Scheduler"))...) + allErrs = append(allErrs, validateIPVSSchedulerMethod(componentconfig.IPVSSchedulerMethod(config.IPVS.Scheduler), newPath.Child("KubeProxyIPVSConfiguration").Child("Scheduler"))...) 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]")) @@ -159,18 +159,18 @@ func validateHostPort(input string, fldPath *field.Path) field.ErrorList { return allErrs } -func validateIPVSSchedulerMethod(scheduler string, fldPath *field.Path) field.ErrorList { - supportedMethod := []string{ - string(componentconfig.RoundRobin), - string(componentconfig.WeightedRoundRobin), - string(componentconfig.LeastConnection), - string(componentconfig.WeightedLeastConnection), - string(componentconfig.LocalityBasedLeastConnection), - string(componentconfig.LocalityBasedLeastConnectionWithReplication), - string(componentconfig.SourceHashing), - string(componentconfig.DestinationHashing), - string(componentconfig.ShortestExpectedDelay), - string(componentconfig.NeverQueue), +func validateIPVSSchedulerMethod(scheduler componentconfig.IPVSSchedulerMethod, fldPath *field.Path) field.ErrorList { + supportedMethod := []componentconfig.IPVSSchedulerMethod{ + componentconfig.RoundRobin, + componentconfig.WeightedRoundRobin, + componentconfig.LeastConnection, + componentconfig.WeightedLeastConnection, + componentconfig.LocalityBasedLeastConnection, + componentconfig.LocalityBasedLeastConnectionWithReplication, + componentconfig.SourceHashing, + componentconfig.DestinationHashing, + componentconfig.ShortestExpectedDelay, + componentconfig.NeverQueue, "", } allErrs := field.ErrorList{} diff --git a/cmd/kube-proxy/app/validation_test.go b/cmd/kube-proxy/app/validation_test.go index c860d1f5409..51d22b3299b 100644 --- a/cmd/kube-proxy/app/validation_test.go +++ b/cmd/kube-proxy/app/validation_test.go @@ -112,7 +112,7 @@ func TestValidateKubeProxyConfiguration(t *testing.T) { config: componentconfig.KubeProxyConfiguration{ BindAddress: "10.10.12.11", HealthzBindAddress: "0.0.0.0:12345", - // only HealthzBindAddress is invalid + // only MetricsBindAddress is invalid MetricsBindAddress: "127.0.0.1", ClusterCIDR: "192.168.59.0/24", UDPIdleTimeout: metav1.Duration{Duration: 1 * time.Second}, @@ -402,3 +402,132 @@ func TestValidateProxyMode(t *testing.T) { } } } + +func TestValidateClientConnectionConfiguration(t *testing.T) { + newPath := field.NewPath("KubeProxyConfiguration") + + successCases := []componentconfig.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 componentconfig.ClientConnectionConfiguration + msg string + }{ + { + ccc: componentconfig.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 := []componentconfig.IPVSSchedulerMethod{ + componentconfig.RoundRobin, + componentconfig.WeightedRoundRobin, + componentconfig.LeastConnection, + componentconfig.WeightedLeastConnection, + componentconfig.LocalityBasedLeastConnection, + componentconfig.LocalityBasedLeastConnectionWithReplication, + componentconfig.SourceHashing, + componentconfig.DestinationHashing, + componentconfig.ShortestExpectedDelay, + componentconfig.NeverQueue, + "", + } + + for _, successCase := range successCases { + if errs := validateIPVSSchedulerMethod(successCase, newPath.Child("Scheduler")); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + + errorCases := []struct { + mode componentconfig.IPVSSchedulerMethod + msg string + }{ + { + mode: componentconfig.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) + } + } +}