namespace: Provide a special status cause when a namespace is terminating
Clients should be able to identify when a namespace is being terminated and take special action such as backing off or giving up. Add a helper for getting the cause of an error and then add a special cause to the forbidden error that namespace lifecycle admission returns. We can't change the forbidden reason without potentially breaking older clients and so cause is the appropriate tool. Add `StatusCause` and `HasStatusCause` to the errors package to make checking for causes simpler. Add `NamespaceTerminatingCause` to the v1 API as a constant. Kubernetes-commit: a62c5b282fda7c0832d329cde45e5e0a836924e8
This commit is contained in:
parent
025332b0ce
commit
3d42d38e70
|
|
@ -170,8 +170,15 @@ func (l *Lifecycle) Admit(ctx context.Context, a admission.Attributes, o admissi
|
|||
return nil
|
||||
}
|
||||
|
||||
// TODO: This should probably not be a 403
|
||||
return admission.NewForbidden(a, fmt.Errorf("unable to create new content in namespace %s because it is being terminated", a.GetNamespace()))
|
||||
err := admission.NewForbidden(a, fmt.Errorf("unable to create new content in namespace %s because it is being terminated", a.GetNamespace()))
|
||||
if apierr, ok := err.(*errors.StatusError); ok {
|
||||
apierr.ErrStatus.Details.Causes = append(apierr.ErrStatus.Details.Causes, metav1.StatusCause{
|
||||
Type: v1.NamespaceTerminatingCause,
|
||||
Message: fmt.Sprintf("namespace %s is being terminated", a.GetNamespace()),
|
||||
Field: "metadata.namespace",
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -19,14 +19,17 @@ package lifecycle
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
|
|
@ -192,6 +195,14 @@ func TestAdmissionNamespaceTerminating(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Errorf("Expected error rejecting creates in a namespace when it is terminating")
|
||||
}
|
||||
expectedCause := metav1.StatusCause{
|
||||
Type: v1.NamespaceTerminatingCause,
|
||||
Message: fmt.Sprintf("namespace %s is being terminated", namespace),
|
||||
Field: "metadata.namespace",
|
||||
}
|
||||
if cause, ok := errors.StatusCause(err, v1.NamespaceTerminatingCause); !ok || !reflect.DeepEqual(expectedCause, cause) {
|
||||
t.Errorf("Expected status cause indicating the namespace is terminating: %t %s", ok, diff.ObjectReflectDiff(expectedCause, cause))
|
||||
}
|
||||
|
||||
// verify update operations in the namespace can proceed
|
||||
err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), nil)
|
||||
|
|
|
|||
Loading…
Reference in New Issue