From 2b569eeea041e279a337eb91625e5d5dea362608 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Wed, 14 Sep 2016 16:01:16 -0400 Subject: [PATCH] compensate for raft/cache delay in namespace admission --- .../namespace/lifecycle/admission.go | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/plugin/pkg/admission/namespace/lifecycle/admission.go b/plugin/pkg/admission/namespace/lifecycle/admission.go index 29eea688195..a083df8ba93 100644 --- a/plugin/pkg/admission/namespace/lifecycle/admission.go +++ b/plugin/pkg/admission/namespace/lifecycle/admission.go @@ -21,6 +21,7 @@ import ( "io" "time" + "github.com/golang/glog" lru "github.com/hashicorp/golang-lru" "k8s.io/kubernetes/pkg/client/cache" @@ -38,6 +39,12 @@ const ( PluginName = "NamespaceLifecycle" // how long a namespace stays in the force live lookup cache before expiration. forceLiveLookupTTL = 30 * time.Second + // how long to wait for a missing namespace before re-checking the cache (and then doing a live lookup) + // this accomplishes two things: + // 1. It allows a watch-fed cache time to observe a namespace creation event + // 2. It allows time for a namespace creation to distribute to members of a storage cluster, + // so the live lookup has a better chance of succeeding even if it isn't performed against the leader. + missingNamespaceWait = 50 * time.Millisecond ) func init() { @@ -113,6 +120,19 @@ func (l *lifecycle) Admit(a admission.Attributes) error { return errors.NewInternalError(err) } + if !exists && a.GetOperation() == admission.Create { + // give the cache time to observe the namespace before rejecting a create. + // this helps when creating a namespace and immediately creating objects within it. + time.Sleep(missingNamespaceWait) + namespaceObj, exists, err = l.namespaceInformer.GetStore().Get(key) + if err != nil { + return errors.NewInternalError(err) + } + if exists { + glog.V(4).Infof("found %s in cache after waiting", a.GetNamespace()) + } + } + // forceLiveLookup if true will skip looking at local cache state and instead always make a live call to server. forceLiveLookup := false lruItemObj, ok := l.forceLiveLookupCache.Get(a.GetNamespace()) @@ -123,7 +143,7 @@ func (l *lifecycle) Admit(a admission.Attributes) error { // refuse to operate on non-existent namespaces if !exists || forceLiveLookup { - // in case of latency in our caches, make a call direct to storage to verify that it truly exists or not + // as a last resort, make a call directly to storage namespaceObj, err = l.client.Core().Namespaces().Get(a.GetNamespace()) if err != nil { if errors.IsNotFound(err) { @@ -131,6 +151,7 @@ func (l *lifecycle) Admit(a admission.Attributes) error { } return errors.NewInternalError(err) } + glog.V(4).Infof("found %s via storage lookup", a.GetNamespace()) } // ensure that we're not trying to create objects in terminating namespaces