// Admit enforces that a namespace must exist in order to associate content with it. // Admit enforces that a namespace that is terminating cannot accept new content being associated with it. func (e *lifecycle) Admit(a admission.Attributes) (err error) { if len(a.GetNamespace()) == 0 { return nil } // always allow a SAR request through, the SAR will return information about // the ability to take action on the object, no need to verify it here. if isSubjectAccessReview(a) { return nil } groupMeta, err := registered.Group(a.GetKind().Group) if err != nil { return err } mapping, err := groupMeta.RESTMapper.RESTMapping(a.GetKind().GroupKind()) if err != nil { glog.V(4).Infof("Ignoring life-cycle enforcement for resource %v; no associated default version and kind could be found.", a.GetResource()) return nil } if mapping.Scope.Name() != meta.RESTScopeNameNamespace { return nil } if !e.cache.Running() { return admission.NewForbidden(a, err) } namespace, err := e.cache.GetNamespace(a.GetNamespace()) if err != nil { return admission.NewForbidden(a, err) } // in case of concurrency issues, we will retry this logic numRetries := 10 interval := time.Duration(rand.Int63n(90)+int64(10)) * time.Millisecond for retry := 1; retry <= numRetries; retry++ { // associate this namespace with openshift _, err = projectutil.Associate(e.client, namespace) if err == nil { break } // we have exhausted all reasonable efforts to retry so give up now if retry == numRetries { return admission.NewForbidden(a, err) } // get the latest namespace for the next pass in case of resource version updates time.Sleep(interval) // it's possible the namespace actually was deleted, so just forbid if this occurs namespace, err = e.client.Core().Namespaces().Get(a.GetNamespace()) if err != nil { return admission.NewForbidden(a, err) } } return nil }
// Admit enforces that a namespace must exist in order to associate content with it. // Admit enforces that a namespace that is terminating cannot accept new content being associated with it. func (e *lifecycle) Admit(a admission.Attributes) (err error) { if len(a.GetNamespace()) == 0 { return nil } // always allow a SAR request through, the SAR will return information about // the ability to take action on the object, no need to verify it here. if isSubjectAccessReview(a) { return nil } mapping, err := latest.RESTMapper.RESTMapping(a.GetKind()) if err != nil { glog.V(4).Infof("Ignoring life-cycle enforcement for resource %v; no associated default version and kind could be found.", a.GetResource()) return nil } if mapping.Scope.Name() != meta.RESTScopeNameNamespace { return nil } // we want to allow someone to delete something in case it was phantom created somehow if a.GetOperation() == "DELETE" { return nil } name := "Unknown" obj := a.GetObject() if obj != nil { name, _ = meta.NewAccessor().Name(obj) } if !e.cache.Running() { return admission.NewForbidden(a, err) } namespace, err := e.cache.GetNamespace(a.GetNamespace()) if err != nil { return admission.NewForbidden(a, err) } if a.GetOperation() != "CREATE" { return nil } if namespace.Status.Phase == kapi.NamespaceTerminating && !e.creatableResources.Has(strings.ToLower(a.GetResource().Resource)) { return apierrors.NewForbidden(a.GetKind().Kind, name, fmt.Errorf("Namespace %s is terminating", a.GetNamespace())) } // in case of concurrency issues, we will retry this logic numRetries := 10 interval := time.Duration(rand.Int63n(90)+int64(10)) * time.Millisecond for retry := 1; retry <= numRetries; retry++ { // associate this namespace with openshift _, err = projectutil.Associate(e.client, namespace) if err == nil { break } // we have exhausted all reasonable efforts to retry so give up now if retry == numRetries { return admission.NewForbidden(a, err) } // get the latest namespace for the next pass in case of resource version updates time.Sleep(interval) // it's possible the namespace actually was deleted, so just forbid if this occurs namespace, err = e.client.Namespaces().Get(a.GetNamespace()) if err != nil { return admission.NewForbidden(a, err) } } return nil }