mirror of
https://github.com/kubernetes/client-go.git
synced 2025-06-22 05:10:32 +00:00
Merge pull request #126038 from mprahl/retry-watcher-forbidden
Stop the RetryWatcher when failing due to permissions issue Kubernetes-commit: e54c8ef2024e638d721242224f6f925b15ee43f5
This commit is contained in:
commit
79827ce1df
@ -128,6 +128,35 @@ func (rw *RetryWatcher) doReceive() (bool, time.Duration) {
|
|||||||
return false, 0
|
return false, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the watch failed due to the client not having permission to watch the resource or the credentials
|
||||||
|
// being invalid (e.g. expired token).
|
||||||
|
if apierrors.IsForbidden(err) || apierrors.IsUnauthorized(err) {
|
||||||
|
// Add more detail since the forbidden message returned by the Kubernetes API is just "unknown".
|
||||||
|
klog.ErrorS(err, msg+": ensure the client has valid credentials and watch permissions on the resource")
|
||||||
|
|
||||||
|
if apiStatus, ok := err.(apierrors.APIStatus); ok {
|
||||||
|
statusErr := apiStatus.Status()
|
||||||
|
|
||||||
|
sent := rw.send(watch.Event{
|
||||||
|
Type: watch.Error,
|
||||||
|
Object: &statusErr,
|
||||||
|
})
|
||||||
|
if !sent {
|
||||||
|
// This likely means the RetryWatcher is stopping but return false so the caller to doReceive can
|
||||||
|
// verify this and potentially retry.
|
||||||
|
klog.Error("Failed to send the Unauthorized or Forbidden watch event")
|
||||||
|
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This should never happen since apierrors only handles apierrors.APIStatus. Still, this is an
|
||||||
|
// unrecoverable error, so still allow it to return true below.
|
||||||
|
klog.ErrorS(err, msg+": encountered an unexpected Unauthorized or Forbidden error type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, 0
|
||||||
|
}
|
||||||
|
|
||||||
klog.ErrorS(err, msg)
|
klog.ErrorS(err, msg)
|
||||||
// Retry
|
// Retry
|
||||||
return false, 0
|
return false, 0
|
||||||
|
@ -288,6 +288,42 @@ func TestRetryWatcher(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "fails on Forbidden",
|
||||||
|
initialRV: "5",
|
||||||
|
watchClient: &cache.ListWatch{
|
||||||
|
WatchFunc: func() func(options metav1.ListOptions) (watch.Interface, error) {
|
||||||
|
return func(options metav1.ListOptions) (watch.Interface, error) {
|
||||||
|
return nil, apierrors.NewForbidden(schema.GroupResource{}, "", errors.New("unknown"))
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
watchCount: 1,
|
||||||
|
expected: []watch.Event{
|
||||||
|
{
|
||||||
|
Type: watch.Error,
|
||||||
|
Object: &apierrors.NewForbidden(schema.GroupResource{}, "", errors.New("unknown")).ErrStatus,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fails on Unauthorized",
|
||||||
|
initialRV: "5",
|
||||||
|
watchClient: &cache.ListWatch{
|
||||||
|
WatchFunc: func() func(options metav1.ListOptions) (watch.Interface, error) {
|
||||||
|
return func(options metav1.ListOptions) (watch.Interface, error) {
|
||||||
|
return nil, apierrors.NewUnauthorized("")
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
watchCount: 1,
|
||||||
|
expected: []watch.Event{
|
||||||
|
{
|
||||||
|
Type: watch.Error,
|
||||||
|
Object: &apierrors.NewUnauthorized("").ErrStatus,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "recovers from timeout error",
|
name: "recovers from timeout error",
|
||||||
initialRV: "5",
|
initialRV: "5",
|
||||||
|
Loading…
Reference in New Issue
Block a user