// memory compares pods by largest consumer of memory relative to request. func memory(stats statsFunc) cmpFunc { return func(p1, p2 *v1.Pod) int { p1Stats, found := stats(p1) // if we have no usage stats for p1, we want p2 first if !found { return -1 } // if we have no usage stats for p2, but p1 has usage, we want p1 first. p2Stats, found := stats(p2) if !found { return 1 } // if we cant get usage for p1 measured, we want p2 first p1Usage, err := podMemoryUsage(p1Stats) if err != nil { return -1 } // if we cant get usage for p2 measured, we want p1 first p2Usage, err := podMemoryUsage(p2Stats) if err != nil { return 1 } // adjust p1, p2 usage relative to the request (if any) p1Memory := p1Usage[v1.ResourceMemory] p1Spec, err := core.PodUsageFunc(p1) if err != nil { return -1 } p1Request := p1Spec[api.ResourceRequestsMemory] p1Memory.Sub(p1Request) p2Memory := p2Usage[v1.ResourceMemory] p2Spec, err := core.PodUsageFunc(p2) if err != nil { return 1 } p2Request := p2Spec[api.ResourceRequestsMemory] p2Memory.Sub(p2Request) // if p2 is using more than p1, we want p2 first return p2Memory.Cmp(p1Memory) } }
// TestAdmissionSetsMissingNamespace verifies that if an object lacks a // namespace, it will be set. func TestAdmissionSetsMissingNamespace(t *testing.T) { namespace := "test" resourceQuota := &api.ResourceQuota{ ObjectMeta: api.ObjectMeta{Name: "quota", Namespace: namespace, ResourceVersion: "124"}, Status: api.ResourceQuotaStatus{ Hard: api.ResourceList{ api.ResourceCPU: resource.MustParse("3"), }, Used: api.ResourceList{ api.ResourceCPU: resource.MustParse("1"), }, }, } kubeClient := fake.NewSimpleClientset(resourceQuota) indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}) computeResources := []api.ResourceName{ api.ResourcePods, api.ResourceCPU, } usageFunc := func(object runtime.Object) api.ResourceList { pod, ok := object.(*api.Pod) if !ok { t.Fatalf("Expected pod, got %T", object) } if pod.Namespace != namespace { t.Errorf("Expected pod with different namespace: %q != %q", pod.Namespace, namespace) } return core.PodUsageFunc(pod) } podEvaluator := &generic.GenericEvaluator{ Name: "Test-Evaluator.Pod", InternalGroupKind: api.Kind("Pod"), InternalOperationResources: map[admission.Operation][]api.ResourceName{ admission.Create: computeResources, }, ConstraintsFunc: core.PodConstraintsFunc, MatchedResourceNames: computeResources, MatchesScopeFunc: core.PodMatchesScopeFunc, UsageFunc: usageFunc, } registry := &generic.GenericRegistry{ InternalEvaluators: map[schema.GroupKind]quota.Evaluator{ podEvaluator.GroupKind(): podEvaluator, }, } stopCh := make(chan struct{}) defer close(stopCh) quotaAccessor, _ := newQuotaAccessor(kubeClient) quotaAccessor.indexer = indexer go quotaAccessor.Run(stopCh) evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, 5, stopCh) evaluator.(*quotaEvaluator).registry = registry handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), evaluator: evaluator, } indexer.Add(resourceQuota) newPod := validPod("pod-without-namespace", 1, getResourceRequirements(getResourceList("1", "2Gi"), getResourceList("", ""))) // unset the namespace newPod.ObjectMeta.Namespace = "" err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)) if err != nil { t.Errorf("Got unexpected error: %v", err) } if newPod.Namespace != namespace { t.Errorf("Got unexpected pod namespace: %q != %q", newPod.Namespace, namespace) } }