本文整理匯總了Golang中k8s/io/kubernetes/pkg/admission.Attributes.GetName方法的典型用法代碼示例。如果您正苦於以下問題:Golang Attributes.GetName方法的具體用法?Golang Attributes.GetName怎麽用?Golang Attributes.GetName使用的例子?那麽, 這裏精選的方法代碼示例或許可以為您提供幫助。您也可以進一步了解該方法所在類k8s/io/kubernetes/pkg/admission.Attributes
的用法示例。
在下文中一共展示了Attributes.GetName方法的15個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。
示例1: Admit
// Admit determines if the service should be admitted based on the configured network CIDR.
func (r *externalIPRanger) Admit(a kadmission.Attributes) error {
if a.GetResource() != kapi.Resource("services") {
return nil
}
svc, ok := a.GetObject().(*kapi.Service)
// if we can't convert then we don't handle this object so just return
if !ok {
return nil
}
var errs field.ErrorList
switch {
// administrator disabled externalIPs
case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) == 0:
errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs"), "externalIPs have been disabled"))
// administrator has limited the range
case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) > 0:
for i, s := range svc.Spec.ExternalIPs {
ip := net.ParseIP(s)
if ip == nil {
errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIPs must be a valid address"))
continue
}
if networkSlice(r.reject).Contains(ip) || !networkSlice(r.admit).Contains(ip) {
errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIP is not allowed"))
continue
}
}
}
if len(errs) > 0 {
return apierrs.NewInvalid(a.GetKind(), a.GetName(), errs)
}
return nil
}
示例2: Admit
func (a *gcPermissionsEnforcement) Admit(attributes admission.Attributes) (err error) {
// if we aren't changing owner references, then the edit is always allowed
if !isChangingOwnerReference(attributes.GetObject(), attributes.GetOldObject()) {
return nil
}
deleteAttributes := authorizer.AttributesRecord{
User: attributes.GetUserInfo(),
Verb: "delete",
Namespace: attributes.GetNamespace(),
APIGroup: attributes.GetResource().Group,
APIVersion: attributes.GetResource().Version,
Resource: attributes.GetResource().Resource,
Subresource: attributes.GetSubresource(),
Name: attributes.GetName(),
ResourceRequest: true,
Path: "",
}
allowed, reason, err := a.authorizer.Authorize(deleteAttributes)
if allowed {
return nil
}
return admission.NewForbidden(attributes, fmt.Errorf("cannot set an ownerRef on a resource you can't delete: %v, %v", reason, err))
}
示例3: Admit
func (l *lifecycle) Admit(a admission.Attributes) (err error) {
// prevent deletion of immortal namespaces
if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == api.Kind("Namespace") && l.immortalNamespaces.Has(a.GetName()) {
return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted"))
}
// if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do
// if we're here, then the API server has found a route, which means that if we have a non-empty namespace
// its a namespaced resource.
if len(a.GetNamespace()) == 0 || a.GetKind().GroupKind() == api.Kind("Namespace") {
// if a namespace is deleted, we want to prevent all further creates into it
// while it is undergoing termination. to reduce incidences where the cache
// is slow to update, we forcefully remove the namespace from our local cache.
// this will cause a live lookup of the namespace to get its latest state even
// before the watch notification is received.
if a.GetOperation() == admission.Delete {
l.store.Delete(&api.Namespace{
ObjectMeta: api.ObjectMeta{
Name: a.GetName(),
},
})
}
return nil
}
namespaceObj, exists, err := l.store.Get(&api.Namespace{
ObjectMeta: api.ObjectMeta{
Name: a.GetNamespace(),
Namespace: "",
},
})
if err != nil {
return errors.NewInternalError(err)
}
// refuse to operate on non-existent namespaces
if !exists {
// 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.Core().Namespaces().Get(a.GetNamespace())
if err != nil {
if errors.IsNotFound(err) {
return err
}
return errors.NewInternalError(err)
}
}
// ensure that we're not trying to create objects in terminating namespaces
if a.GetOperation() == admission.Create {
namespace := namespaceObj.(*api.Namespace)
if namespace.Status.Phase != api.NamespaceTerminating {
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()))
}
return nil
}
示例4: Admit
func (d *sccExecRestrictions) Admit(a admission.Attributes) (err error) {
if a.GetOperation() != admission.Connect {
return nil
}
if a.GetResource() != kapi.Resource("pods") {
return nil
}
if a.GetSubresource() != "attach" && a.GetSubresource() != "exec" {
return nil
}
pod, err := d.client.Pods(a.GetNamespace()).Get(a.GetName())
if err != nil {
return admission.NewForbidden(a, err)
}
// create a synthentic admission attribute to check SCC admission status for this pod
// clear the SA name, so that any permissions MUST be based on your user's power, not the SAs power.
pod.Spec.ServiceAccountName = ""
createAttributes := admission.NewAttributesRecord(pod, kapi.Kind("Pod"), a.GetNamespace(), a.GetName(), a.GetResource(), a.GetSubresource(), admission.Create, a.GetUserInfo())
if err := d.constraintAdmission.Admit(createAttributes); err != nil {
return admission.NewForbidden(a, err)
}
return nil
}
示例5: Admit
func (d *sccExecRestrictions) Admit(a admission.Attributes) (err error) {
if a.GetOperation() != admission.Connect {
return nil
}
if a.GetResource().GroupResource() != kapi.Resource("pods") {
return nil
}
if a.GetSubresource() != "attach" && a.GetSubresource() != "exec" {
return nil
}
pod, err := d.client.Core().Pods(a.GetNamespace()).Get(a.GetName())
if err != nil {
return admission.NewForbidden(a, err)
}
// TODO, if we want to actually limit who can use which service account, then we'll need to add logic here to make sure that
// we're allowed to use the SA the pod is using. Otherwise, user-A creates pod and user-B (who can't use the SA) can exec into it.
createAttributes := admission.NewAttributesRecord(pod, pod, kapi.Kind("Pod").WithVersion(""), a.GetNamespace(), a.GetName(), a.GetResource(), "", admission.Create, a.GetUserInfo())
if err := d.constraintAdmission.Admit(createAttributes); err != nil {
return admission.NewForbidden(a, err)
}
return nil
}
示例6: Admit
// Admit determines if the service should be admitted based on the configured network CIDR.
func (r *externalIPRanger) Admit(a kadmission.Attributes) error {
if a.GetResource().GroupResource() != kapi.Resource("services") {
return nil
}
svc, ok := a.GetObject().(*kapi.Service)
// if we can't convert then we don't handle this object so just return
if !ok {
return nil
}
// Determine if an ingress ip address should be allowed as an
// external ip by checking the loadbalancer status of the previous
// object state. Only updates need to be validated against the
// ingress ip since the loadbalancer status cannot be set on
// create.
ingressIP := ""
retrieveIngressIP := a.GetOperation() == kadmission.Update &&
r.allowIngressIP && svc.Spec.Type == kapi.ServiceTypeLoadBalancer
if retrieveIngressIP {
old, ok := a.GetOldObject().(*kapi.Service)
ipPresent := ok && old != nil && len(old.Status.LoadBalancer.Ingress) > 0
if ipPresent {
ingressIP = old.Status.LoadBalancer.Ingress[0].IP
}
}
var errs field.ErrorList
switch {
// administrator disabled externalIPs
case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) == 0:
onlyIngressIP := len(svc.Spec.ExternalIPs) == 1 && svc.Spec.ExternalIPs[0] == ingressIP
if !onlyIngressIP {
errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs"), "externalIPs have been disabled"))
}
// administrator has limited the range
case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) > 0:
for i, s := range svc.Spec.ExternalIPs {
ip := net.ParseIP(s)
if ip == nil {
errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIPs must be a valid address"))
continue
}
notIngressIP := s != ingressIP
if (NetworkSlice(r.reject).Contains(ip) || !NetworkSlice(r.admit).Contains(ip)) && notIngressIP {
errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIP is not allowed"))
continue
}
}
}
if len(errs) > 0 {
return apierrs.NewInvalid(a.GetKind().GroupKind(), a.GetName(), errs)
}
return nil
}
示例7: checkAccess
func (r *restrictedEndpointsAdmission) checkAccess(attr kadmission.Attributes) (bool, error) {
ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), attr.GetNamespace()), attr.GetUserInfo())
authzAttr := authorizer.DefaultAuthorizationAttributes{
Verb: "create",
Resource: authorizationapi.RestrictedEndpointsResource,
APIGroup: kapi.GroupName,
ResourceName: attr.GetName(),
}
allow, _, err := r.authorizer.Authorize(ctx, authzAttr)
return allow, err
}
示例8: Admit
func (l *lifecycle) Admit(a admission.Attributes) (err error) {
// prevent deletion of immortal namespaces
if a.GetOperation() == admission.Delete && a.GetKind() == "Namespace" && l.immortalNamespaces.Has(a.GetName()) {
return errors.NewForbidden(a.GetKind(), a.GetName(), fmt.Errorf("this namespace may not be deleted"))
}
gvk, err := api.RESTMapper.KindFor(a.GetResource())
if err != nil {
return errors.NewInternalError(err)
}
mapping, err := api.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return errors.NewInternalError(err)
}
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
return nil
}
namespaceObj, exists, err := l.store.Get(&api.Namespace{
ObjectMeta: api.ObjectMeta{
Name: a.GetNamespace(),
Namespace: "",
},
})
if err != nil {
return errors.NewInternalError(err)
}
// refuse to operate on non-existent namespaces
if !exists {
// 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 {
if errors.IsNotFound(err) {
return err
}
return errors.NewInternalError(err)
}
}
// ensure that we're not trying to create objects in terminating namespaces
if a.GetOperation() == admission.Create {
namespace := namespaceObj.(*api.Namespace)
if namespace.Status.Phase != api.NamespaceTerminating {
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()))
}
return nil
}
示例9: checkPodsBindAccess
// build LocalSubjectAccessReview struct to validate role via checkAccess
func (o *podNodeConstraints) checkPodsBindAccess(attr admission.Attributes) (bool, error) {
ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), attr.GetNamespace()), attr.GetUserInfo())
authzAttr := authorizer.DefaultAuthorizationAttributes{
Verb: "create",
Resource: "pods/binding",
APIGroup: kapi.GroupName,
}
if attr.GetResource().GroupResource() == kapi.Resource("pods") {
authzAttr.ResourceName = attr.GetName()
}
allow, _, err := o.authorizer.Authorize(ctx, authzAttr)
return allow, err
}
示例10: Admit
func (l *lifecycle) Admit(a admission.Attributes) (err error) {
// prevent deletion of immortal namespaces
if a.GetOperation() == admission.Delete {
if a.GetKind() == "Namespace" && l.immortalNamespaces.Has(a.GetName()) {
return errors.NewForbidden(a.GetKind(), a.GetName(), fmt.Errorf("namespace can never be deleted"))
}
return nil
}
defaultVersion, kind, err := api.RESTMapper.VersionAndKindForResource(a.GetResource())
if err != nil {
return admission.NewForbidden(a, err)
}
mapping, err := api.RESTMapper.RESTMapping(kind, defaultVersion)
if err != nil {
return admission.NewForbidden(a, err)
}
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
return nil
}
namespaceObj, exists, err := l.store.Get(&api.Namespace{
ObjectMeta: api.ObjectMeta{
Name: a.GetNamespace(),
Namespace: "",
},
})
if err != nil {
return admission.NewForbidden(a, err)
}
if !exists {
return nil
}
namespace := namespaceObj.(*api.Namespace)
if namespace.Status.Phase != api.NamespaceTerminating {
return nil
}
return admission.NewForbidden(a, fmt.Errorf("Unable to create new content in namespace %s because it is being terminated.", a.GetNamespace()))
}
示例11: Admit
// Admit attempts to apply the image policy to the incoming resource.
func (a *imagePolicyPlugin) Admit(attr admission.Attributes) error {
switch attr.GetOperation() {
case admission.Create, admission.Update:
if len(attr.GetSubresource()) > 0 {
return nil
}
// only create and update are tested, and only on core resources
// TODO: scan all resources
// TODO: Create a general equivalence map for admission - operation X on subresource Y is equivalent to reduced operation
default:
return nil
}
gr := attr.GetResource().GroupResource()
if !a.accepter.Covers(gr) {
return nil
}
m, err := meta.GetImageReferenceMutator(attr.GetObject())
if err != nil {
return apierrs.NewForbidden(gr, attr.GetName(), fmt.Errorf("unable to apply image policy against objects of type %T: %v", attr.GetObject(), err))
}
// load exclusion rules from the namespace cache
var excluded sets.String
if ns := attr.GetNamespace(); len(ns) > 0 {
if ns, err := a.projectCache.GetNamespace(ns); err == nil {
if value := ns.Annotations[api.IgnorePolicyRulesAnnotation]; len(value) > 0 {
excluded = sets.NewString(strings.Split(value, ",")...)
}
}
}
if err := accept(a.accepter, a.resolver, m, attr, excluded); err != nil {
return err
}
return nil
}
示例12: accept
func accept(accepter rules.Accepter, resolver imageResolver, m meta.ImageReferenceMutator, attr admission.Attributes, excludedRules sets.String) error {
var decisions policyDecisions
gr := attr.GetResource().GroupResource()
requiresImage := accepter.RequiresImage(gr)
resolvesImage := accepter.ResolvesImage(gr)
errs := m.Mutate(func(ref *kapi.ObjectReference) error {
// create the attribute set for this particular reference, if we have never seen the reference
// before
decision, ok := decisions[*ref]
if !ok {
var attrs *rules.ImagePolicyAttributes
var err error
if requiresImage || resolvesImage {
// convert the incoming reference into attributes to pass to the accepter
attrs, err = resolver.ResolveObjectReference(ref, attr.GetNamespace())
}
// if the incoming reference is of a Kind that needed a lookup, but that lookup failed,
// use the most generic policy rule here because we don't even know the image name
if attrs == nil {
attrs = &rules.ImagePolicyAttributes{}
// an objectref that is DockerImage ref will have a name that corresponds to its pull spec. We can parse that
// to a docker image ref
if ref != nil && ref.Kind == "DockerImage" {
attrs.Name, _ = imageapi.ParseDockerImageReference(ref.Name)
}
}
attrs.Resource = gr
attrs.ExcludedRules = excludedRules
decision.attrs = attrs
decision.err = err
}
// we only need to test a given input once for acceptance
if !decision.tested {
accepted := accepter.Accepts(decision.attrs)
glog.V(5).Infof("Made decision for %v (as: %v, err: %v): %t", ref, decision.attrs.Name, decision.err, accepted)
// remember this decision for any identical reference
if decisions == nil {
decisions = make(policyDecisions)
}
decision.tested = true
decisions[*ref] = decision
if !accepted {
// if the image is rejected, return the resolution error, if any
if decision.err != nil {
return decision.err
}
return errRejectByPolicy
}
}
// if resolution was requested, and no error was present, transform the
// reference back into a string to a DockerImage
if resolvesImage && decision.err == nil {
ref.Namespace = ""
ref.Name = decision.attrs.Name.Exact()
ref.Kind = "DockerImage"
}
if decision.err != nil {
glog.V(5).Infof("Ignored resolution error for %v: %v", ref, decision.err)
}
return nil
})
for i := range errs {
errs[i].Type = field.ErrorTypeForbidden
if errs[i].Detail != errRejectByPolicy.Error() {
errs[i].Detail = fmt.Sprintf("this image is prohibited by policy: %s", errs[i].Detail)
}
}
if len(errs) > 0 {
glog.V(5).Infof("failed to create: %v", errs)
return apierrs.NewInvalid(attr.GetKind().GroupKind(), attr.GetName(), errs)
}
glog.V(5).Infof("allowed: %#v", attr)
return nil
}
示例13: accept
func accept(accepter rules.Accepter, imageResolutionType imagepolicyapi.ImageResolutionType, resolver imageResolver, m meta.ImageReferenceMutator, attr admission.Attributes, excludedRules sets.String) error {
decisions := policyDecisions{}
gr := attr.GetResource().GroupResource()
errs := m.Mutate(func(ref *kapi.ObjectReference) error {
// create the attribute set for this particular reference, if we have never seen the reference
// before
decision, ok := decisions[*ref]
if !ok {
if imagepolicyapi.RequestsResolution(imageResolutionType) {
resolvedAttrs, err := resolver.ResolveObjectReference(ref, attr.GetNamespace())
switch {
case err != nil && imagepolicyapi.FailOnResolutionFailure(imageResolutionType):
// if we had a resolution error and we're supposed to fail, fail
decision.err = err
decision.tested = true
decisions[*ref] = decision
return err
case err != nil:
// if we had an error, but aren't supposed to fail, just don't do anything else and keep track of
// the resolution failure
decision.err = err
case err == nil:
// if we resolved properly, assign the attributes and rewrite the pull spec if we need to
decision.attrs = resolvedAttrs
if imagepolicyapi.RewriteImagePullSpec(imageResolutionType) {
ref.Namespace = ""
ref.Name = decision.attrs.Name.Exact()
ref.Kind = "DockerImage"
}
}
}
// if we don't have any image policy attributes, attempt a best effort parse for the remaining tests
if decision.attrs == nil {
decision.attrs = &rules.ImagePolicyAttributes{}
// an objectref that is DockerImage ref will have a name that corresponds to its pull spec. We can parse that
// to a docker image ref
if ref != nil && ref.Kind == "DockerImage" {
decision.attrs.Name, _ = imageapi.ParseDockerImageReference(ref.Name)
}
}
decision.attrs.Resource = gr
decision.attrs.ExcludedRules = excludedRules
}
// we only need to test a given input once for acceptance
if !decision.tested {
accepted := accepter.Accepts(decision.attrs)
glog.V(5).Infof("Made decision for %v (as: %v, err: %v): %t", ref, decision.attrs.Name, decision.err, accepted)
decision.tested = true
decisions[*ref] = decision
if !accepted {
// if the image is rejected, return the resolution error, if any
if decision.err != nil {
return decision.err
}
return errRejectByPolicy
}
}
return nil
})
for i := range errs {
errs[i].Type = field.ErrorTypeForbidden
if errs[i].Detail != errRejectByPolicy.Error() {
errs[i].Detail = fmt.Sprintf("this image is prohibited by policy: %s", errs[i].Detail)
}
}
if len(errs) > 0 {
glog.V(5).Infof("failed to create: %v", errs)
return apierrs.NewInvalid(attr.GetKind().GroupKind(), attr.GetName(), errs)
}
glog.V(5).Infof("allowed: %#v", attr)
return nil
}
示例14: checkRequest
// checkRequest verifies that the request does not exceed any quota constraint. it returns back a copy of quotas not yet persisted
// that capture what the usage would be if the request succeeded. It return an error if the is insufficient quota to satisfy the request
func (e *quotaEvaluator) checkRequest(quotas []api.ResourceQuota, a admission.Attributes) ([]api.ResourceQuota, error) {
namespace := a.GetNamespace()
name := a.GetName()
evaluators := e.registry.Evaluators()
evaluator, found := evaluators[a.GetKind().GroupKind()]
if !found {
return quotas, nil
}
op := a.GetOperation()
operationResources := evaluator.OperationResources(op)
if len(operationResources) == 0 {
return quotas, nil
}
// find the set of quotas that are pertinent to this request
// reject if we match the quota, but usage is not calculated yet
// reject if the input object does not satisfy quota constraints
// if there are no pertinent quotas, we can just return
inputObject := a.GetObject()
interestingQuotaIndexes := []int{}
for i := range quotas {
resourceQuota := quotas[i]
match := evaluator.Matches(&resourceQuota, inputObject)
if !match {
continue
}
hardResources := quota.ResourceNames(resourceQuota.Status.Hard)
evaluatorResources := evaluator.MatchesResources()
requiredResources := quota.Intersection(hardResources, evaluatorResources)
err := evaluator.Constraints(requiredResources, inputObject)
if err != nil {
return nil, admission.NewForbidden(a, fmt.Errorf("Failed quota: %s: %v", resourceQuota.Name, err))
}
if !hasUsageStats(&resourceQuota) {
return nil, admission.NewForbidden(a, fmt.Errorf("Status unknown for quota: %s", resourceQuota.Name))
}
interestingQuotaIndexes = append(interestingQuotaIndexes, i)
}
if len(interestingQuotaIndexes) == 0 {
return quotas, nil
}
// Usage of some resources cannot be counted in isolation. For example when
// the resource represents a number of unique references to external
// resource. In such a case an evaluator needs to process other objects in
// the same namespace which needs to be known.
if accessor, err := meta.Accessor(inputObject); namespace != "" && err == nil {
if accessor.GetNamespace() == "" {
accessor.SetNamespace(namespace)
}
}
// there is at least one quota that definitely matches our object
// as a result, we need to measure the usage of this object for quota
// on updates, we need to subtract the previous measured usage
// if usage shows no change, just return since it has no impact on quota
deltaUsage := evaluator.Usage(inputObject)
if admission.Update == op {
prevItem, err := evaluator.Get(namespace, name)
if err != nil {
return nil, admission.NewForbidden(a, fmt.Errorf("Unable to get previous: %v", err))
}
prevUsage := evaluator.Usage(prevItem)
deltaUsage = quota.Subtract(deltaUsage, prevUsage)
}
if quota.IsZero(deltaUsage) {
return quotas, nil
}
for _, index := range interestingQuotaIndexes {
resourceQuota := quotas[index]
hardResources := quota.ResourceNames(resourceQuota.Status.Hard)
requestedUsage := quota.Mask(deltaUsage, hardResources)
newUsage := quota.Add(resourceQuota.Status.Used, requestedUsage)
if allowed, exceeded := quota.LessThanOrEqual(newUsage, resourceQuota.Status.Hard); !allowed {
failedRequestedUsage := quota.Mask(requestedUsage, exceeded)
failedUsed := quota.Mask(resourceQuota.Status.Used, exceeded)
failedHard := quota.Mask(resourceQuota.Status.Hard, exceeded)
return nil, admission.NewForbidden(a,
fmt.Errorf("Exceeded quota: %s, requested: %s, used: %s, limited: %s",
resourceQuota.Name,
prettyPrint(failedRequestedUsage),
prettyPrint(failedUsed),
prettyPrint(failedHard)))
}
// update to the new usage number
quotas[index].Status.Used = newUsage
}
return quotas, nil
}
示例15: Admit
func (l *lifecycle) Admit(a admission.Attributes) error {
// prevent deletion of immortal namespaces
if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == api.Kind("Namespace") && l.immortalNamespaces.Has(a.GetName()) {
return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted"))
}
// if we're here, then we've already passed authentication, so we're allowed to do what we're trying to do
// if we're here, then the API server has found a route, which means that if we have a non-empty namespace
// its a namespaced resource.
if len(a.GetNamespace()) == 0 || a.GetKind().GroupKind() == api.Kind("Namespace") {
// if a namespace is deleted, we want to prevent all further creates into it
// while it is undergoing termination. to reduce incidences where the cache
// is slow to update, we add the namespace into a force live lookup list to ensure
// we are not looking at stale state.
if a.GetOperation() == admission.Delete {
newEntry := forceLiveLookupEntry{
expiry: time.Now().Add(forceLiveLookupTTL),
}
l.forceLiveLookupCache.Add(a.GetName(), newEntry)
}
return nil
}
// we need to wait for our caches to warm
if !l.WaitForReady() {
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
}
var (
namespaceObj interface{}
exists bool
err error
)
key := makeNamespaceKey(a.GetNamespace())
namespaceObj, exists, err = l.namespaceInformer.GetStore().Get(key)
if err != nil {
return errors.NewInternalError(err)
}
// 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())
if ok && lruItemObj.(forceLiveLookupEntry).expiry.Before(time.Now()) {
// we think the namespace was marked for deletion, but our current local cache says otherwise, we will force a live lookup.
forceLiveLookup = exists && namespaceObj.(*api.Namespace).Status.Phase == api.NamespaceActive
}
// 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
namespaceObj, err = l.client.Core().Namespaces().Get(a.GetNamespace())
if err != nil {
if errors.IsNotFound(err) {
return err
}
return errors.NewInternalError(err)
}
}
// ensure that we're not trying to create objects in terminating namespaces
if a.GetOperation() == admission.Create {
namespace := namespaceObj.(*api.Namespace)
if namespace.Status.Phase != api.NamespaceTerminating {
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()))
}
return nil
}