From 3890c26b265fedf2db19ac47bfbc827aaca25df7 Mon Sep 17 00:00:00 2001 From: Piotr Szczesniak Date: Tue, 15 Sep 2015 21:05:52 +0200 Subject: [PATCH] Added annotation that InitialResources set request --- .../admission/initialresources/admission.go | 23 +++++- .../initialresources/admission_test.go | 73 +++++++++++++------ 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/plugin/pkg/admission/initialresources/admission.go b/plugin/pkg/admission/initialresources/admission.go index 090092cefef..e594633f7e3 100644 --- a/plugin/pkg/admission/initialresources/admission.go +++ b/plugin/pkg/admission/initialresources/admission.go @@ -36,9 +36,10 @@ var ( ) const ( - samplesThreshold = 60 - week = 7 * 24 * time.Hour - month = 30 * 24 * time.Hour + initialResourcesAnnotation = "kubernetes.io/initial-resources" + samplesThreshold = 60 + week = 7 * 24 * time.Hour + month = 30 * 24 * time.Hour ) // WARNING: this feature is experimental and will definitely change. @@ -81,6 +82,7 @@ func (ir initialResources) Admit(a admission.Attributes) (err error) { // The method veryfies whether resources should be set for the given pod and // if there is estimation available the method fills Request field. func (ir initialResources) estimateAndFillResourcesIfNotSet(pod *api.Pod) { + annotations := []string{} for i := range pod.Spec.Containers { c := &pod.Spec.Containers[i] req := c.Resources.Requests @@ -109,16 +111,29 @@ func (ir initialResources) estimateAndFillResourcesIfNotSet(pod *api.Pod) { c.Resources.Requests = api.ResourceList{} req = c.Resources.Requests } + setRes := []string{} if cpu != nil { glog.Infof("CPU estimation for container %v in pod %v/%v is %v", c.Name, pod.ObjectMeta.Namespace, pod.ObjectMeta.Name, cpu.String()) + setRes = append(setRes, string(api.ResourceCPU)) req[api.ResourceCPU] = *cpu } if mem != nil { glog.Infof("Memory estimation for container %v in pod %v/%v is %v", c.Name, pod.ObjectMeta.Namespace, pod.ObjectMeta.Name, mem.String()) + setRes = append(setRes, string(api.ResourceMemory)) req[api.ResourceMemory] = *mem } + if len(setRes) > 0 { + a := strings.Join(setRes, ", ") + " request for container " + c.Name + annotations = append(annotations, a) + } + } + if len(annotations) > 0 { + if pod.ObjectMeta.Annotations == nil { + pod.ObjectMeta.Annotations = make(map[string]string) + } + val := "Initial Resources plugin set: " + strings.Join(annotations, "; ") + pod.ObjectMeta.Annotations[initialResourcesAnnotation] = val } - // TODO(piosz): verify the estimates fits in LimitRanger } func (ir initialResources) getEstimation(kind api.ResourceName, c *api.Container) (*resource.Quantity, error) { diff --git a/plugin/pkg/admission/initialresources/admission_test.go b/plugin/pkg/admission/initialresources/admission_test.go index 2bfaada487c..40ec120cf4d 100644 --- a/plugin/pkg/admission/initialresources/admission_test.go +++ b/plugin/pkg/admission/initialresources/admission_test.go @@ -55,18 +55,18 @@ func addContainer(pod *api.Pod, name, image string, request api.ResourceList) { }) } -func createPod(name string, image string, request api.ResourceList) api.Pod { - pod := api.Pod{ +func createPod(name string, image string, request api.ResourceList) *api.Pod { + pod := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: "test"}, Spec: api.PodSpec{}, } pod.Spec.Containers = []api.Container{} - addContainer(&pod, "c0", image, request) + addContainer(pod, "c0", image, request) return pod } -func getPods() []api.Pod { - return []api.Pod{ +func getPods() []*api.Pod { + return []*api.Pod{ createPod("p0", "image:v0", parseReq("", "")), createPod("p1", "image:v1", parseReq("", "300")), createPod("p2", "image:v2", parseReq("300m", "")), @@ -88,9 +88,25 @@ func verifyPod(t *testing.T, pod *api.Pod, cpu, mem int64) { verifyContainer(t, &pod.Spec.Containers[0], cpu, mem) } -func admit(t *testing.T, ir admission.Interface, pods []api.Pod) { +func verifyAnnotation(t *testing.T, pod *api.Pod, expected string) { + a, ok := pod.ObjectMeta.Annotations[initialResourcesAnnotation] + if !ok { + t.Errorf("No annotation but expected %v", expected) + } + if a != expected { + t.Errorf("Wrong annatation set by Initial Resources: got %v, expected %v", a, expected) + } +} + +func expectNoAnnotation(t *testing.T, pod *api.Pod) { + if a, ok := pod.ObjectMeta.Annotations[initialResourcesAnnotation]; ok { + t.Errorf("Expected no annatation but got %v", a) + } +} + +func admit(t *testing.T, ir admission.Interface, pods []*api.Pod) { for i := range pods { - p := &pods[i] + p := pods[i] if err := ir.Admit(admission.NewAttributesRecord(p, "Pod", "test", p.ObjectMeta.Name, "pods", "", admission.Create, nil)); err != nil { t.Error(err) } @@ -109,10 +125,15 @@ func TestEstimationBasedOnTheSameImage7d(t *testing.T) { pods := getPods() admit(t, ir, pods) - verifyPod(t, &pods[0], 100, 100) - verifyPod(t, &pods[1], 100, 300) - verifyPod(t, &pods[2], 300, 100) - verifyPod(t, &pods[3], 300, 300) + verifyPod(t, pods[0], 100, 100) + verifyPod(t, pods[1], 100, 300) + verifyPod(t, pods[2], 300, 100) + verifyPod(t, pods[3], 300, 300) + + verifyAnnotation(t, pods[0], "Initial Resources plugin set: cpu, memory request for container c0") + verifyAnnotation(t, pods[1], "Initial Resources plugin set: cpu request for container c0") + verifyAnnotation(t, pods[2], "Initial Resources plugin set: memory request for container c0") + expectNoAnnotation(t, pods[3]) } func TestEstimationBasedOnTheSameImage30d(t *testing.T) { @@ -130,10 +151,10 @@ func TestEstimationBasedOnTheSameImage30d(t *testing.T) { pods := getPods() admit(t, ir, pods) - verifyPod(t, &pods[0], 100, 100) - verifyPod(t, &pods[1], 100, 300) - verifyPod(t, &pods[2], 300, 100) - verifyPod(t, &pods[3], 300, 300) + verifyPod(t, pods[0], 100, 100) + verifyPod(t, pods[1], 100, 300) + verifyPod(t, pods[2], 300, 100) + verifyPod(t, pods[3], 300, 300) } func TestEstimationBasedOnOtherImages(t *testing.T) { @@ -148,10 +169,10 @@ func TestEstimationBasedOnOtherImages(t *testing.T) { pods := getPods() admit(t, ir, pods) - verifyPod(t, &pods[0], 100, 100) - verifyPod(t, &pods[1], 100, 300) - verifyPod(t, &pods[2], 300, 100) - verifyPod(t, &pods[3], 300, 300) + verifyPod(t, pods[0], 100, 100) + verifyPod(t, pods[1], 100, 300) + verifyPod(t, pods[2], 300, 100) + verifyPod(t, pods[3], 300, 300) } func TestNoData(t *testing.T) { @@ -160,7 +181,7 @@ func TestNoData(t *testing.T) { } ir := newInitialResources(&fakeSource{f: f}) - pods := []api.Pod{ + pods := []*api.Pod{ createPod("p0", "image:v0", parseReq("", "")), } admit(t, ir, pods) @@ -168,6 +189,8 @@ func TestNoData(t *testing.T) { if pods[0].Spec.Containers[0].Resources.Requests != nil { t.Errorf("Unexpected resource estimation") } + + expectNoAnnotation(t, pods[0]) } func TestManyContainers(t *testing.T) { @@ -180,13 +203,15 @@ func TestManyContainers(t *testing.T) { ir := newInitialResources(&fakeSource{f: f}) pod := createPod("p", "image:v0", parseReq("", "")) - addContainer(&pod, "c1", "image:v1", parseReq("", "300")) - addContainer(&pod, "c2", "image:v2", parseReq("300m", "")) - addContainer(&pod, "c3", "image:v3", parseReq("300m", "300")) - admit(t, ir, []api.Pod{pod}) + addContainer(pod, "c1", "image:v1", parseReq("", "300")) + addContainer(pod, "c2", "image:v2", parseReq("300m", "")) + addContainer(pod, "c3", "image:v3", parseReq("300m", "300")) + admit(t, ir, []*api.Pod{pod}) verifyContainer(t, &pod.Spec.Containers[0], 100, 100) verifyContainer(t, &pod.Spec.Containers[1], 100, 300) verifyContainer(t, &pod.Spec.Containers[2], 300, 100) verifyContainer(t, &pod.Spec.Containers[3], 300, 300) + + verifyAnnotation(t, pod, "Initial Resources plugin set: cpu, memory request for container c0; cpu request for container c1; memory request for container c2") }