Re-allow 0 for kube-proxy conntrack settings

When kube-proxy was refactored to use a configuration file, the ability
to use 0 for conntrack min, max, max per core, and tcp timeouts was
inadvertently broken; if you specified 0, it would instead apply the
default value from defaults.go.

This change restores the ability to use 0 to mean 0.

Signed-off-by: Andy Goldstein <andy.goldstein@gmail.com>
This commit is contained in:
Andy Goldstein 2017-11-07 12:41:49 -05:00
parent ff82be09e6
commit ea78586832
10 changed files with 250 additions and 154 deletions

View File

@ -146,12 +146,15 @@ func AddFlags(options *Options, fs *pflag.FlagSet) {
fs.Float32Var(&options.config.ClientConnection.QPS, "kube-api-qps", options.config.ClientConnection.QPS, "QPS to use while talking with kubernetes apiserver") fs.Float32Var(&options.config.ClientConnection.QPS, "kube-api-qps", options.config.ClientConnection.QPS, "QPS to use while talking with kubernetes apiserver")
fs.IntVar(&options.config.ClientConnection.Burst, "kube-api-burst", options.config.ClientConnection.Burst, "Burst to use while talking with kubernetes apiserver") fs.IntVar(&options.config.ClientConnection.Burst, "kube-api-burst", options.config.ClientConnection.Burst, "Burst to use while talking with kubernetes apiserver")
fs.DurationVar(&options.config.UDPIdleTimeout.Duration, "udp-timeout", options.config.UDPIdleTimeout.Duration, "How long an idle UDP connection will be kept open (e.g. '250ms', '2s'). Must be greater than 0. Only applicable for proxy-mode=userspace") fs.DurationVar(&options.config.UDPIdleTimeout.Duration, "udp-timeout", options.config.UDPIdleTimeout.Duration, "How long an idle UDP connection will be kept open (e.g. '250ms', '2s'). Must be greater than 0. Only applicable for proxy-mode=userspace")
fs.Int32Var(&options.config.Conntrack.Max, "conntrack-max", options.config.Conntrack.Max, if options.config.Conntrack.Max == nil {
options.config.Conntrack.Max = utilpointer.Int32Ptr(0)
}
fs.Int32Var(options.config.Conntrack.Max, "conntrack-max", *options.config.Conntrack.Max,
"Maximum number of NAT connections to track (0 to leave as-is). This overrides conntrack-max-per-core and conntrack-min.") "Maximum number of NAT connections to track (0 to leave as-is). This overrides conntrack-max-per-core and conntrack-min.")
fs.MarkDeprecated("conntrack-max", "This feature will be removed in a later release.") fs.MarkDeprecated("conntrack-max", "This feature will be removed in a later release.")
fs.Int32Var(&options.config.Conntrack.MaxPerCore, "conntrack-max-per-core", options.config.Conntrack.MaxPerCore, fs.Int32Var(options.config.Conntrack.MaxPerCore, "conntrack-max-per-core", *options.config.Conntrack.MaxPerCore,
"Maximum number of NAT connections to track per CPU core (0 to leave the limit as-is and ignore conntrack-min).") "Maximum number of NAT connections to track per CPU core (0 to leave the limit as-is and ignore conntrack-min).")
fs.Int32Var(&options.config.Conntrack.Min, "conntrack-min", options.config.Conntrack.Min, fs.Int32Var(options.config.Conntrack.Min, "conntrack-min", *options.config.Conntrack.Min,
"Minimum number of conntrack entries to allocate, regardless of conntrack-max-per-core (set conntrack-max-per-core=0 to leave the limit as-is).") "Minimum number of conntrack entries to allocate, regardless of conntrack-max-per-core (set conntrack-max-per-core=0 to leave the limit as-is).")
fs.DurationVar(&options.config.Conntrack.TCPEstablishedTimeout.Duration, "conntrack-tcp-timeout-established", options.config.Conntrack.TCPEstablishedTimeout.Duration, "Idle timeout for established TCP connections (0 to leave as-is)") fs.DurationVar(&options.config.Conntrack.TCPEstablishedTimeout.Duration, "conntrack-tcp-timeout-established", options.config.Conntrack.TCPEstablishedTimeout.Duration, "Idle timeout for established TCP connections (0 to leave as-is)")
fs.DurationVar( fs.DurationVar(
@ -179,6 +182,17 @@ func (o *Options) Complete() error {
o.applyDeprecatedHealthzPortToConfig() o.applyDeprecatedHealthzPortToConfig()
} }
// Load the config file here in Complete, so that Validate validates the fully-resolved config.
if len(o.ConfigFile) > 0 {
if c, err := o.loadConfigFromFile(o.ConfigFile); err != nil {
return err
} else {
o.config = c
// Make sure we apply the feature gate settings in the config file.
utilfeature.DefaultFeatureGate.Set(o.config.FeatureGates)
}
}
return nil return nil
} }
@ -196,23 +210,11 @@ func (o *Options) Validate(args []string) error {
} }
func (o *Options) Run() error { func (o *Options) Run() error {
config := o.config
if len(o.WriteConfigTo) > 0 { if len(o.WriteConfigTo) > 0 {
return o.writeConfigFile() return o.writeConfigFile()
} }
if len(o.ConfigFile) > 0 { proxyServer, err := NewProxyServer(o.config, o.CleanupAndExit, o.scheme, o.master)
if c, err := o.loadConfigFromFile(o.ConfigFile); err != nil {
return err
} else {
config = c
// Make sure we apply the feature gate settings in the config file.
utilfeature.DefaultFeatureGate.Set(config.FeatureGates)
}
}
proxyServer, err := NewProxyServer(config, o.CleanupAndExit, o.scheme, o.master)
if err != nil { if err != nil {
return err return err
} }
@ -502,14 +504,14 @@ func (s *ProxyServer) Run() error {
} }
} }
if s.ConntrackConfiguration.TCPEstablishedTimeout.Duration > 0 { if s.ConntrackConfiguration.TCPEstablishedTimeout != nil && s.ConntrackConfiguration.TCPEstablishedTimeout.Duration > 0 {
timeout := int(s.ConntrackConfiguration.TCPEstablishedTimeout.Duration / time.Second) timeout := int(s.ConntrackConfiguration.TCPEstablishedTimeout.Duration / time.Second)
if err := s.Conntracker.SetTCPEstablishedTimeout(timeout); err != nil { if err := s.Conntracker.SetTCPEstablishedTimeout(timeout); err != nil {
return err return err
} }
} }
if s.ConntrackConfiguration.TCPCloseWaitTimeout.Duration > 0 { if s.ConntrackConfiguration.TCPCloseWaitTimeout != nil && s.ConntrackConfiguration.TCPCloseWaitTimeout.Duration > 0 {
timeout := int(s.ConntrackConfiguration.TCPCloseWaitTimeout.Duration / time.Second) timeout := int(s.ConntrackConfiguration.TCPCloseWaitTimeout.Duration / time.Second)
if err := s.Conntracker.SetTCPCloseWaitTimeout(timeout); err != nil { if err := s.Conntracker.SetTCPCloseWaitTimeout(timeout); err != nil {
return err return err
@ -548,16 +550,19 @@ func (s *ProxyServer) birthCry() {
} }
func getConntrackMax(config kubeproxyconfig.KubeProxyConntrackConfiguration) (int, error) { func getConntrackMax(config kubeproxyconfig.KubeProxyConntrackConfiguration) (int, error) {
if config.Max > 0 { if config.Max != nil && *config.Max > 0 {
if config.MaxPerCore > 0 { if config.MaxPerCore != nil && *config.MaxPerCore > 0 {
return -1, fmt.Errorf("invalid config: Conntrack Max and Conntrack MaxPerCore are mutually exclusive") return -1, fmt.Errorf("invalid config: Conntrack Max and Conntrack MaxPerCore are mutually exclusive")
} }
glog.V(3).Infof("getConntrackMax: using absolute conntrack-max (deprecated)") glog.V(3).Infof("getConntrackMax: using absolute conntrack-max (deprecated)")
return int(config.Max), nil return int(*config.Max), nil
} }
if config.MaxPerCore > 0 { if config.MaxPerCore != nil && *config.MaxPerCore > 0 {
floor := int(config.Min) floor := 0
scaled := int(config.MaxPerCore) * goruntime.NumCPU() if config.Min != nil {
floor = int(*config.Min)
}
scaled := int(*config.MaxPerCore) * goruntime.NumCPU()
if scaled > floor { if scaled > floor {
glog.V(3).Infof("getConntrackMax: using scaled conntrack-max-per-core") glog.V(3).Infof("getConntrackMax: using scaled conntrack-max-per-core")
return scaled, nil return scaled, nil

View File

@ -203,9 +203,9 @@ func TestGetConntrackMax(t *testing.T) {
for i, tc := range testCases { for i, tc := range testCases {
cfg := kubeproxyconfig.KubeProxyConntrackConfiguration{ cfg := kubeproxyconfig.KubeProxyConntrackConfiguration{
Min: tc.min, Min: utilpointer.Int32Ptr(tc.min),
Max: tc.max, Max: utilpointer.Int32Ptr(tc.max),
MaxPerCore: tc.maxPerCore, MaxPerCore: utilpointer.Int32Ptr(tc.maxPerCore),
} }
x, e := getConntrackMax(cfg) x, e := getConntrackMax(cfg)
if e != nil { if e != nil {
@ -344,11 +344,11 @@ udpTimeoutMilliseconds: 123ms
ClusterCIDR: tc.clusterCIDR, ClusterCIDR: tc.clusterCIDR,
ConfigSyncPeriod: metav1.Duration{Duration: 15 * time.Second}, ConfigSyncPeriod: metav1.Duration{Duration: 15 * time.Second},
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: 4, Max: utilpointer.Int32Ptr(4),
MaxPerCore: 2, MaxPerCore: utilpointer.Int32Ptr(2),
Min: 1, Min: utilpointer.Int32Ptr(1),
TCPCloseWaitTimeout: metav1.Duration{Duration: 10 * time.Second}, TCPCloseWaitTimeout: &metav1.Duration{Duration: 10 * time.Second},
TCPEstablishedTimeout: metav1.Duration{Duration: 20 * time.Second}, TCPEstablishedTimeout: &metav1.Duration{Duration: 20 * time.Second},
}, },
FeatureGates: "all", FeatureGates: "all",
HealthzBindAddress: tc.healthzBindAddress, HealthzBindAddress: tc.healthzBindAddress,

View File

@ -73,21 +73,21 @@ type KubeProxyIPVSConfiguration struct {
// the Kubernetes proxy server. // the Kubernetes proxy server.
type KubeProxyConntrackConfiguration struct { type KubeProxyConntrackConfiguration struct {
// max is the maximum number of NAT connections to track (0 to // max is the maximum number of NAT connections to track (0 to
// leave as-is). This takes precedence over conntrackMaxPerCore and conntrackMin. // leave as-is). This takes precedence over maxPerCore and min.
Max int32 Max *int32
// maxPerCore is the maximum number of NAT connections to track // maxPerCore is the maximum number of NAT connections to track
// per CPU core (0 to leave the limit as-is and ignore conntrackMin). // per CPU core (0 to leave the limit as-is and ignore min).
MaxPerCore int32 MaxPerCore *int32
// min is the minimum value of connect-tracking records to allocate, // min is the minimum value of connect-tracking records to allocate,
// regardless of conntrackMaxPerCore (set conntrackMaxPerCore=0 to leave the limit as-is). // regardless of maxPerCore (set maxPerCore=0 to leave the limit as-is).
Min int32 Min *int32
// tcpEstablishedTimeout is how long an idle TCP connection will be kept open // tcpEstablishedTimeout is how long an idle TCP connection will be kept open
// (e.g. '2s'). Must be greater than 0. // (e.g. '2s'). Must be greater than 0 to set.
TCPEstablishedTimeout metav1.Duration TCPEstablishedTimeout *metav1.Duration
// tcpCloseWaitTimeout is how long an idle conntrack entry // tcpCloseWaitTimeout is how long an idle conntrack entry
// in CLOSE_WAIT state will remain in the conntrack // in CLOSE_WAIT state will remain in the conntrack
// table. (e.g. '60s'). Must be greater than 0 to set. // table. (e.g. '60s'). Must be greater than 0 to set.
TCPCloseWaitTimeout metav1.Duration TCPCloseWaitTimeout *metav1.Duration
} }
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -25,6 +25,7 @@ import (
kruntime "k8s.io/apimachinery/pkg/runtime" kruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/kubelet/qos" "k8s.io/kubernetes/pkg/kubelet/qos"
"k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/master/ports"
"k8s.io/kubernetes/pkg/util/pointer"
) )
func addDefaultingFuncs(scheme *kruntime.Scheme) error { func addDefaultingFuncs(scheme *kruntime.Scheme) error {
@ -63,23 +64,23 @@ func SetDefaults_KubeProxyConfiguration(obj *KubeProxyConfiguration) {
obj.UDPIdleTimeout = metav1.Duration{Duration: 250 * time.Millisecond} obj.UDPIdleTimeout = metav1.Duration{Duration: 250 * time.Millisecond}
} }
// If ConntrackMax is set, respect it. // If ConntrackMax is set, respect it.
if obj.Conntrack.Max == 0 { if obj.Conntrack.Max == nil {
// If ConntrackMax is *not* set, use per-core scaling. // If ConntrackMax is *not* set, use per-core scaling.
if obj.Conntrack.MaxPerCore == 0 { if obj.Conntrack.MaxPerCore == nil {
obj.Conntrack.MaxPerCore = 32 * 1024 obj.Conntrack.MaxPerCore = pointer.Int32Ptr(32 * 1024)
} }
if obj.Conntrack.Min == 0 { if obj.Conntrack.Min == nil {
obj.Conntrack.Min = 128 * 1024 obj.Conntrack.Min = pointer.Int32Ptr(128 * 1024)
} }
} }
if obj.IPTables.MasqueradeBit == nil { if obj.IPTables.MasqueradeBit == nil {
temp := int32(14) temp := int32(14)
obj.IPTables.MasqueradeBit = &temp obj.IPTables.MasqueradeBit = &temp
} }
if obj.Conntrack.TCPEstablishedTimeout == zero { if obj.Conntrack.TCPEstablishedTimeout == nil {
obj.Conntrack.TCPEstablishedTimeout = metav1.Duration{Duration: 24 * time.Hour} // 1 day (1/5 default) obj.Conntrack.TCPEstablishedTimeout = &metav1.Duration{Duration: 24 * time.Hour} // 1 day (1/5 default)
} }
if obj.Conntrack.TCPCloseWaitTimeout == zero { if obj.Conntrack.TCPCloseWaitTimeout == nil {
// See https://github.com/kubernetes/kubernetes/issues/32551. // See https://github.com/kubernetes/kubernetes/issues/32551.
// //
// CLOSE_WAIT conntrack state occurs when the Linux kernel // CLOSE_WAIT conntrack state occurs when the Linux kernel
@ -100,7 +101,7 @@ func SetDefaults_KubeProxyConfiguration(obj *KubeProxyConfiguration) {
// //
// We set CLOSE_WAIT to one hour by default to better match // We set CLOSE_WAIT to one hour by default to better match
// typical server timeouts. // typical server timeouts.
obj.Conntrack.TCPCloseWaitTimeout = metav1.Duration{Duration: 1 * time.Hour} obj.Conntrack.TCPCloseWaitTimeout = &metav1.Duration{Duration: 1 * time.Hour}
} }
if obj.ConfigSyncPeriod.Duration == 0 { if obj.ConfigSyncPeriod.Duration == 0 {
obj.ConfigSyncPeriod.Duration = 15 * time.Minute obj.ConfigSyncPeriod.Duration = 15 * time.Minute

View File

@ -69,21 +69,21 @@ type KubeProxyIPVSConfiguration struct {
// the Kubernetes proxy server. // the Kubernetes proxy server.
type KubeProxyConntrackConfiguration struct { type KubeProxyConntrackConfiguration struct {
// max is the maximum number of NAT connections to track (0 to // max is the maximum number of NAT connections to track (0 to
// leave as-is). This takes precedence over conntrackMaxPerCore and conntrackMin. // leave as-is). This takes precedence over maxPerCore and min.
Max int32 `json:"max"` Max *int32 `json:"max"`
// maxPerCore is the maximum number of NAT connections to track // maxPerCore is the maximum number of NAT connections to track
// per CPU core (0 to leave the limit as-is and ignore conntrackMin). // per CPU core (0 to leave the limit as-is and ignore min).
MaxPerCore int32 `json:"maxPerCore"` MaxPerCore *int32 `json:"maxPerCore"`
// min is the minimum value of connect-tracking records to allocate, // min is the minimum value of connect-tracking records to allocate,
// regardless of conntrackMaxPerCore (set conntrackMaxPerCore=0 to leave the limit as-is). // regardless of conntrackMaxPerCore (set maxPerCore=0 to leave the limit as-is).
Min int32 `json:"min"` Min *int32 `json:"min"`
// tcpEstablishedTimeout is how long an idle TCP connection will be kept open // tcpEstablishedTimeout is how long an idle TCP connection will be kept open
// (e.g. '2s'). Must be greater than 0. // (e.g. '2s'). Must be greater than 0 to set.
TCPEstablishedTimeout metav1.Duration `json:"tcpEstablishedTimeout"` TCPEstablishedTimeout *metav1.Duration `json:"tcpEstablishedTimeout"`
// tcpCloseWaitTimeout is how long an idle conntrack entry // tcpCloseWaitTimeout is how long an idle conntrack entry
// in CLOSE_WAIT state will remain in the conntrack // in CLOSE_WAIT state will remain in the conntrack
// table. (e.g. '60s'). Must be greater than 0 to set. // table. (e.g. '60s'). Must be greater than 0 to set.
TCPCloseWaitTimeout metav1.Duration `json:"tcpCloseWaitTimeout"` TCPCloseWaitTimeout *metav1.Duration `json:"tcpCloseWaitTimeout"`
} }
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -21,6 +21,7 @@ limitations under the License.
package v1alpha1 package v1alpha1
import ( import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion" conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig" kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
@ -145,11 +146,11 @@ func Convert_kubeproxyconfig_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfigu
} }
func autoConvert_v1alpha1_KubeProxyConntrackConfiguration_To_kubeproxyconfig_KubeProxyConntrackConfiguration(in *KubeProxyConntrackConfiguration, out *kubeproxyconfig.KubeProxyConntrackConfiguration, s conversion.Scope) error { func autoConvert_v1alpha1_KubeProxyConntrackConfiguration_To_kubeproxyconfig_KubeProxyConntrackConfiguration(in *KubeProxyConntrackConfiguration, out *kubeproxyconfig.KubeProxyConntrackConfiguration, s conversion.Scope) error {
out.Max = in.Max out.Max = (*int32)(unsafe.Pointer(in.Max))
out.MaxPerCore = in.MaxPerCore out.MaxPerCore = (*int32)(unsafe.Pointer(in.MaxPerCore))
out.Min = in.Min out.Min = (*int32)(unsafe.Pointer(in.Min))
out.TCPEstablishedTimeout = in.TCPEstablishedTimeout out.TCPEstablishedTimeout = (*v1.Duration)(unsafe.Pointer(in.TCPEstablishedTimeout))
out.TCPCloseWaitTimeout = in.TCPCloseWaitTimeout out.TCPCloseWaitTimeout = (*v1.Duration)(unsafe.Pointer(in.TCPCloseWaitTimeout))
return nil return nil
} }
@ -159,11 +160,11 @@ func Convert_v1alpha1_KubeProxyConntrackConfiguration_To_kubeproxyconfig_KubePro
} }
func autoConvert_kubeproxyconfig_KubeProxyConntrackConfiguration_To_v1alpha1_KubeProxyConntrackConfiguration(in *kubeproxyconfig.KubeProxyConntrackConfiguration, out *KubeProxyConntrackConfiguration, s conversion.Scope) error { func autoConvert_kubeproxyconfig_KubeProxyConntrackConfiguration_To_v1alpha1_KubeProxyConntrackConfiguration(in *kubeproxyconfig.KubeProxyConntrackConfiguration, out *KubeProxyConntrackConfiguration, s conversion.Scope) error {
out.Max = in.Max out.Max = (*int32)(unsafe.Pointer(in.Max))
out.MaxPerCore = in.MaxPerCore out.MaxPerCore = (*int32)(unsafe.Pointer(in.MaxPerCore))
out.Min = in.Min out.Min = (*int32)(unsafe.Pointer(in.Min))
out.TCPEstablishedTimeout = in.TCPEstablishedTimeout out.TCPEstablishedTimeout = (*v1.Duration)(unsafe.Pointer(in.TCPEstablishedTimeout))
out.TCPCloseWaitTimeout = in.TCPCloseWaitTimeout out.TCPCloseWaitTimeout = (*v1.Duration)(unsafe.Pointer(in.TCPCloseWaitTimeout))
return nil return nil
} }

View File

@ -21,6 +21,7 @@ limitations under the License.
package v1alpha1 package v1alpha1
import ( import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion" conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
reflect "reflect" reflect "reflect"
@ -92,7 +93,7 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
} }
} }
out.UDPIdleTimeout = in.UDPIdleTimeout out.UDPIdleTimeout = in.UDPIdleTimeout
out.Conntrack = in.Conntrack in.Conntrack.DeepCopyInto(&out.Conntrack)
out.ConfigSyncPeriod = in.ConfigSyncPeriod out.ConfigSyncPeriod = in.ConfigSyncPeriod
return return
} }
@ -119,8 +120,51 @@ func (in *KubeProxyConfiguration) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeProxyConntrackConfiguration) DeepCopyInto(out *KubeProxyConntrackConfiguration) { func (in *KubeProxyConntrackConfiguration) DeepCopyInto(out *KubeProxyConntrackConfiguration) {
*out = *in *out = *in
out.TCPEstablishedTimeout = in.TCPEstablishedTimeout if in.Max != nil {
out.TCPCloseWaitTimeout = in.TCPCloseWaitTimeout in, out := &in.Max, &out.Max
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
if in.MaxPerCore != nil {
in, out := &in.MaxPerCore, &out.MaxPerCore
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
if in.Min != nil {
in, out := &in.Min, &out.Min
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
if in.TCPEstablishedTimeout != nil {
in, out := &in.TCPEstablishedTimeout, &out.TCPEstablishedTimeout
if *in == nil {
*out = nil
} else {
*out = new(v1.Duration)
**out = **in
}
}
if in.TCPCloseWaitTimeout != nil {
in, out := &in.TCPCloseWaitTimeout, &out.TCPCloseWaitTimeout
if *in == nil {
*out = nil
} else {
*out = new(v1.Duration)
**out = **in
}
}
return return
} }

View File

@ -93,24 +93,24 @@ func validateKubeProxyIPTablesConfiguration(config kubeproxyconfig.KubeProxyIPTa
func validateKubeProxyConntrackConfiguration(config kubeproxyconfig.KubeProxyConntrackConfiguration, fldPath *field.Path) field.ErrorList { func validateKubeProxyConntrackConfiguration(config kubeproxyconfig.KubeProxyConntrackConfiguration, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if config.Max < 0 { if config.Max != nil && *config.Max < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("Max"), config.Max, "must be greater than or equal to 0")) allErrs = append(allErrs, field.Invalid(fldPath.Child("Max"), config.Max, "must be greater than or equal to 0"))
} }
if config.MaxPerCore < 0 { if config.MaxPerCore != nil && *config.MaxPerCore < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("MaxPerCore"), config.MaxPerCore, "must be greater than or equal to 0")) allErrs = append(allErrs, field.Invalid(fldPath.Child("MaxPerCore"), config.MaxPerCore, "must be greater than or equal to 0"))
} }
if config.Min < 0 { if config.Min != nil && *config.Min < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("Min"), config.Min, "must be greater than or equal to 0")) allErrs = append(allErrs, field.Invalid(fldPath.Child("Min"), config.Min, "must be greater than or equal to 0"))
} }
if config.TCPEstablishedTimeout.Duration <= 0 { if config.TCPEstablishedTimeout.Duration < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("TCPEstablishedTimeout"), config.TCPEstablishedTimeout, "must be greater than 0")) allErrs = append(allErrs, field.Invalid(fldPath.Child("TCPEstablishedTimeout"), config.TCPEstablishedTimeout, "must be greater than or equal to 0"))
} }
if config.TCPCloseWaitTimeout.Duration <= 0 { if config.TCPCloseWaitTimeout.Duration < 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("TCPCloseWaitTimeout"), config.TCPCloseWaitTimeout, "must be greater than 0")) allErrs = append(allErrs, field.Invalid(fldPath.Child("TCPCloseWaitTimeout"), config.TCPCloseWaitTimeout, "must be greater than or equal to 0"))
} }
return allErrs return allErrs

View File

@ -24,6 +24,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig" "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig"
"k8s.io/kubernetes/pkg/util/pointer"
) )
func TestValidateKubeProxyConfiguration(t *testing.T) { func TestValidateKubeProxyConfiguration(t *testing.T) {
@ -41,11 +42,11 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
}, },
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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},
}, },
}, },
} }
@ -75,11 +76,11 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
}, },
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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: "not a valid textual representation of an IP address", msg: "not a valid textual representation of an IP address",
@ -99,11 +100,11 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
}, },
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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 IP:port", msg: "must be IP:port",
@ -123,11 +124,11 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
}, },
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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 IP:port", msg: "must be IP:port",
@ -147,11 +148,11 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
}, },
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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 a valid CIDR block (e.g. 10.100.0.0/16)", msg: "must be a valid CIDR block (e.g. 10.100.0.0/16)",
@ -171,11 +172,11 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
}, },
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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 0", msg: "must be greater than 0",
@ -195,11 +196,11 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
}, },
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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 0", msg: "must be greater than 0",
@ -282,18 +283,18 @@ func TestValidateKubeProxyIPTablesConfiguration(t *testing.T) {
func TestValidateKubeProxyConntrackConfiguration(t *testing.T) { func TestValidateKubeProxyConntrackConfiguration(t *testing.T) {
successCases := []kubeproxyconfig.KubeProxyConntrackConfiguration{ successCases := []kubeproxyconfig.KubeProxyConntrackConfiguration{
{ {
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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},
}, },
{ {
Max: 0, Max: pointer.Int32Ptr(0),
MaxPerCore: 0, MaxPerCore: pointer.Int32Ptr(0),
Min: 0, Min: pointer.Int32Ptr(0),
TCPEstablishedTimeout: metav1.Duration{Duration: 5 * time.Second}, TCPEstablishedTimeout: &metav1.Duration{Duration: 0 * time.Second},
TCPCloseWaitTimeout: metav1.Duration{Duration: 60 * time.Second}, TCPCloseWaitTimeout: &metav1.Duration{Duration: 0 * time.Second},
}, },
} }
newPath := field.NewPath("KubeProxyConfiguration") newPath := field.NewPath("KubeProxyConfiguration")
@ -309,53 +310,53 @@ func TestValidateKubeProxyConntrackConfiguration(t *testing.T) {
}{ }{
{ {
config: kubeproxyconfig.KubeProxyConntrackConfiguration{ config: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(-1), Max: pointer.Int32Ptr(-1),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(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", msg: "must be greater than or equal to 0",
}, },
{ {
config: kubeproxyconfig.KubeProxyConntrackConfiguration{ config: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(-1), MaxPerCore: pointer.Int32Ptr(-1),
Min: int32(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", msg: "must be greater than or equal to 0",
}, },
{ {
config: kubeproxyconfig.KubeProxyConntrackConfiguration{ config: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(2), Max: pointer.Int32Ptr(2),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(-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", msg: "must be greater than or equal to 0",
}, },
{ {
config: kubeproxyconfig.KubeProxyConntrackConfiguration{ config: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(4), Max: pointer.Int32Ptr(4),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(3), Min: pointer.Int32Ptr(3),
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 0", msg: "must be greater than or equal to 0",
}, },
{ {
config: kubeproxyconfig.KubeProxyConntrackConfiguration{ config: kubeproxyconfig.KubeProxyConntrackConfiguration{
Max: int32(4), Max: pointer.Int32Ptr(4),
MaxPerCore: int32(1), MaxPerCore: pointer.Int32Ptr(1),
Min: int32(3), Min: pointer.Int32Ptr(3),
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 0", msg: "must be greater than or equal to 0",
}, },
} }

View File

@ -21,6 +21,7 @@ limitations under the License.
package kubeproxyconfig package kubeproxyconfig
import ( import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion" conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
reflect "reflect" reflect "reflect"
@ -92,7 +93,7 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
} }
} }
out.UDPIdleTimeout = in.UDPIdleTimeout out.UDPIdleTimeout = in.UDPIdleTimeout
out.Conntrack = in.Conntrack in.Conntrack.DeepCopyInto(&out.Conntrack)
out.ConfigSyncPeriod = in.ConfigSyncPeriod out.ConfigSyncPeriod = in.ConfigSyncPeriod
return return
} }
@ -119,8 +120,51 @@ func (in *KubeProxyConfiguration) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeProxyConntrackConfiguration) DeepCopyInto(out *KubeProxyConntrackConfiguration) { func (in *KubeProxyConntrackConfiguration) DeepCopyInto(out *KubeProxyConntrackConfiguration) {
*out = *in *out = *in
out.TCPEstablishedTimeout = in.TCPEstablishedTimeout if in.Max != nil {
out.TCPCloseWaitTimeout = in.TCPCloseWaitTimeout in, out := &in.Max, &out.Max
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
if in.MaxPerCore != nil {
in, out := &in.MaxPerCore, &out.MaxPerCore
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
if in.Min != nil {
in, out := &in.Min, &out.Min
if *in == nil {
*out = nil
} else {
*out = new(int32)
**out = **in
}
}
if in.TCPEstablishedTimeout != nil {
in, out := &in.TCPEstablishedTimeout, &out.TCPEstablishedTimeout
if *in == nil {
*out = nil
} else {
*out = new(v1.Duration)
**out = **in
}
}
if in.TCPCloseWaitTimeout != nil {
in, out := &in.TCPCloseWaitTimeout, &out.TCPCloseWaitTimeout
if *in == nil {
*out = nil
} else {
*out = new(v1.Duration)
**out = **in
}
}
return return
} }