Change:
Currently the admission controller returns a forbidden (403) error if the namespace doesn't exist. We should return a 404 error instead.

Discussion:
import ( "k8s.io/kubernetes/pkg/api" apierrors "k8s.io/kubernetes/pkg/api/errors" <ins> errs "k8s.io/kubernetes/pkg/util/errors" </ins> ) <del> // NewForbidden is a utility function to return a well-formatted admission control error response func NewForbidden(a Attributes, internalError error) error { // do not double wrap an error of same type if apierrors.IsForbidden(internalError) { return internalError } name := "Unknown" kind := a.GetKind() </del> <ins> func extractKindName(a Attributes) (name, kind string, err error) { name = "Unknown" kind = a.GetKind() </ins> obj := a.GetObject() if obj != nil { objectMeta, err := api.ObjectMetaFor(obj) if err != nil { <del> return apierrors.NewForbidden(kind, name, internalError) </del> <ins> return "", "", err </ins> } // this is necessary because name object name generation has not occurred yet

name = objectMeta.GenerateName } } <ins> return name, kind, nil } // NewForbidden is a utility function to return a well-formatted admission control error response func NewForbidden(a Attributes, internalError error) error { // do not double wrap an error of same type if apierrors.IsForbidden(internalError) { return internalError } name, kind, err := extractKindName(a) if err != nil { return apierrors.NewInternalError(errs.NewAggregate([]error{internalError, err})) } </ins> return apierrors.NewForbidden(kind, name, internalError) } <ins> // NewNotFound is a utility function to return a well-formatted admission control error response func NewNotFound(a Attributes) error { name, kind, err := extractKindName(a) if err != nil { return apierrors.NewInternalError(err) } return apierrors.NewNotFound(kind, name) } </ins>

package exists import ( <del> "fmt" </del> "io" "time" "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" <ins> "k8s.io/kubernetes/pkg/api/errors" </ins> "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/client/cache" client "k8s.io/kubernetes/pkg/client/unversioned"

func (e *exists) Admit(a admission.Attributes) (err error) { defaultVersion, kind, err := api.RESTMapper.VersionAndKindForResource(a.GetResource()) if err != nil { <del> return admission.NewForbidden(a, err) </del> <ins> return errors.NewInternalError(err) </ins> } mapping, err := api.RESTMapper.RESTMapping(kind, defaultVersion) if err != nil { <del> return admission.NewForbidden(a, err) </del> <ins> return errors.NewInternalError(err) </ins> } if mapping.Scope.Name() != meta.RESTScopeNameNamespace { return nil

} _, exists, err := e.store.Get(namespace) if err != nil { <del> return admission.NewForbidden(a, err) </del> <ins> return errors.NewInternalError(err) </ins> } if exists { return nil

// in case of latency in our caches, make a call direct to storage to verify that it truly exists or not _, err = e.client.Namespaces().Get(a.GetNamespace()) if err != nil { <del> return admission.NewForbidden(a, fmt.Errorf("Namespace %s does not exist", a.GetNamespace())) </del> <ins> if errors.IsNotFound(err) { return err } return errors.NewInternalError(err) </ins> } return nil

defaultVersion, kind, err := api.RESTMapper.VersionAndKindForResource(a.GetResource()) if err != nil { <del> return admission.NewForbidden(a, err) </del> <ins> return errors.NewInternalError(err) </ins> } mapping, err := api.RESTMapper.RESTMapping(kind, defaultVersion) if err != nil { <del> return admission.NewForbidden(a, err) </del> <ins> return errors.NewInternalError(err) </ins> } if mapping.Scope.Name() != meta.RESTScopeNameNamespace { return nil

}, }) if err != nil { <del> return admission.NewForbidden(a, err) </del> <ins> return errors.NewInternalError(err) </ins> } // refuse to operate on non-existent namespaces

// in case of latency in our caches, make a call direct to storage to verify that it truly exists or not namespaceObj, err = l.client.Namespaces().Get(a.GetNamespace()) if err != nil { <del> return admission.NewForbidden(a, fmt.Errorf("Namespace %s does not exist", a.GetNamespace())) </del> <ins> return admission.NewNotFound(a) </ins> } }

return nil } <ins> // TODO: This should probably not be a 403 </ins> return admission.NewForbidden(a, fmt.Errorf("Unable to create new content in namespace %s because it is being terminated.", a.GetNamespace())) }