mirror of
https://github.com/kubernetes/client-go.git
synced 2025-06-21 12:48:30 +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
|
||||
}
|
||||
|
||||
// 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)
|
||||
// Retry
|
||||
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",
|
||||
initialRV: "5",
|
||||
|
Loading…
Reference in New Issue
Block a user