Merge pull request #55261 from ncdc/kube-proxy-config-fix-conntrack-zero-values

Automatic merge from submit-queue (batch tested with PRs 55247, 55324, 55261, 55147, 54052). 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>.

Restore kube-proxy's support for 0 values for conntrack settings

**What this PR does / why we need it**: re-allow 0 values for kube-proxy conntrack min, max, max per core, tcp close wait timeout, tcp established timeout.

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #50787

**Special notes for your reviewer**:
- I adjusted validation to allow for 0 values for some of the conntrack settings, as otherwise the "leave the limit as-is" logic wouldn't be allowed.
- I moved the loading of the config file from the cobra command's Validate method to Complete. This way, the config is fully resolved before validation happens. Otherwise, it just validates the default config values first, and _then_ the config is loaded.
- I think I got all the default values & nil checking correct, but please review carefully!

**Release note**:

```release-note
Restored kube-proxy's support for 0 values for conntrack min, max, max per core, tcp close wait timeout, and tcp established timeout.
```
This commit is contained in:
Kubernetes Submit Queue 2017-11-09 00:59:23 -08:00 committed by GitHub
commit d28fccfabe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 252 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

@ -21,6 +21,7 @@ go_library(
"//pkg/kubelet/qos:go_default_library", "//pkg/kubelet/qos:go_default_library",
"//pkg/master/ports:go_default_library", "//pkg/master/ports:go_default_library",
"//pkg/proxy/apis/kubeproxyconfig:go_default_library", "//pkg/proxy/apis/kubeproxyconfig:go_default_library",
"//pkg/util/pointer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library", "//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",

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

@ -38,6 +38,7 @@ go_test(
library = ":go_default_library", library = ":go_default_library",
deps = [ deps = [
"//pkg/proxy/apis/kubeproxyconfig:go_default_library", "//pkg/proxy/apis/kubeproxyconfig:go_default_library",
"//pkg/util/pointer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
], ],

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
} }