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:
Clayton Coleman 2019-10-19 22:57:21 -04:00 committed by Kubernetes Publisher
parent 025332b0ce
commit 3d42d38e70
2 changed files with 20 additions and 2 deletions

View File

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

View File

@ -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)