From 3cec9098020ecc168573c7ee658282954dac2a2e Mon Sep 17 00:00:00 2001 From: likakuli <1154584512@qq.com> Date: Tue, 20 Aug 2019 12:18:46 +0800 Subject: [PATCH] fixes a bug that connection refused error cannot be recognized correctly --- .../k8s.io/apimachinery/pkg/util/net/util.go | 17 +++++++++++ .../apimachinery/pkg/util/net/util_test.go | 28 +++++++++++++++++++ .../src/k8s.io/client-go/tools/cache/BUILD | 1 + .../k8s.io/client-go/tools/cache/reflector.go | 14 +++------- .../client-go/tools/cache/reflector_test.go | 2 +- 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/util.go b/staging/src/k8s.io/apimachinery/pkg/util/net/util.go index 8344d10c83a..2e7cb949946 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/net/util.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/util.go @@ -54,3 +54,20 @@ func IsConnectionReset(err error) bool { } return false } + +// Returns if the given err is "connection refused" error +func IsConnectionRefused(err error) bool { + if urlErr, ok := err.(*url.Error); ok { + err = urlErr.Err + } + if opErr, ok := err.(*net.OpError); ok { + err = opErr.Err + } + if osErr, ok := err.(*os.SyscallError); ok { + err = osErr.Err + } + if errno, ok := err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED { + return true + } + return false +} diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/util_test.go b/staging/src/k8s.io/apimachinery/pkg/util/net/util_test.go index bcbef753b74..33fa351e1d8 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/net/util_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/util_test.go @@ -18,6 +18,9 @@ package net import ( "net" + "net/url" + "os" + "syscall" "testing" ) @@ -66,3 +69,28 @@ func TestIPNetEqual(t *testing.T) { } } } + +func TestIsConnectionRefused(t *testing.T) { + testCases := []struct { + err error + expect bool + }{ + { + &url.Error{Err: &net.OpError{Err: syscall.ECONNRESET}}, + false, + }, + { + &url.Error{Err: &net.OpError{Err: syscall.ECONNREFUSED}}, + true, + }, + {&url.Error{Err: &net.OpError{Err: &os.SyscallError{Err: syscall.ECONNREFUSED}}}, + true, + }, + } + + for _, tc := range testCases { + if result := IsConnectionRefused(tc.err); result != tc.expect { + t.Errorf("Expect to be %v, but actual is %v", tc.expect, result) + } + } +} diff --git a/staging/src/k8s.io/client-go/tools/cache/BUILD b/staging/src/k8s.io/client-go/tools/cache/BUILD index 339bfab8f88..3824d2a8174 100644 --- a/staging/src/k8s.io/client-go/tools/cache/BUILD +++ b/staging/src/k8s.io/client-go/tools/cache/BUILD @@ -76,6 +76,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/naming:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", diff --git a/staging/src/k8s.io/client-go/tools/cache/reflector.go b/staging/src/k8s.io/client-go/tools/cache/reflector.go index 4c14aaf7875..8abde7131a3 100644 --- a/staging/src/k8s.io/client-go/tools/cache/reflector.go +++ b/staging/src/k8s.io/client-go/tools/cache/reflector.go @@ -22,11 +22,8 @@ import ( "fmt" "io" "math/rand" - "net" - "net/url" "reflect" "sync" - "syscall" "time" apierrs "k8s.io/apimachinery/pkg/api/errors" @@ -35,6 +32,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/naming" + utilnet "k8s.io/apimachinery/pkg/util/net" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" @@ -285,13 +283,9 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error { // It doesn't make sense to re-list all objects because most likely we will be able to restart // watch where we ended. // If that's the case wait and resend watch request. - if urlError, ok := err.(*url.Error); ok { - if opError, ok := urlError.Err.(*net.OpError); ok { - if errno, ok := opError.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED { - time.Sleep(time.Second) - continue - } - } + if utilnet.IsConnectionRefused(err) { + time.Sleep(time.Second) + continue } return nil } diff --git a/staging/src/k8s.io/client-go/tools/cache/reflector_test.go b/staging/src/k8s.io/client-go/tools/cache/reflector_test.go index caa0723231f..a62638c36fb 100644 --- a/staging/src/k8s.io/client-go/tools/cache/reflector_test.go +++ b/staging/src/k8s.io/client-go/tools/cache/reflector_test.go @@ -24,7 +24,7 @@ import ( "testing" "time" - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait"