Skip to content

Commit 785ccf4

Browse files
committed
Merge pull request kubernetes#12005 from JanetKuo/kubectl-describe-allocatedresource
Make kubectl describe node include allocated resource
2 parents e899a36 + 0ac6dba commit 785ccf4

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

pkg/api/resource/quantity.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,14 @@ func (q *Quantity) String() string {
301301
return number + string(suffix)
302302
}
303303

304+
func (q *Quantity) Add(y Quantity) error {
305+
if q.Format != y.Format {
306+
return fmt.Errorf("format mismatch: %v vs. %v", q.Format, y.Format)
307+
}
308+
q.Amount.Add(q.Amount, y.Amount)
309+
return nil
310+
}
311+
304312
// MarshalJSON implements the json.Marshaller interface.
305313
func (q Quantity) MarshalJSON() ([]byte, error) {
306314
return []byte(`"` + q.String() + `"`), nil

pkg/kubectl/describe.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,17 @@ func describeNode(node *api.Node, pods []*api.Pod, events *api.EventList) (strin
870870
}
871871
}
872872

873+
runningPods := filterNonRunningPods(pods)
874+
reqs, err := getPodsTotalRequests(runningPods)
875+
if err != nil {
876+
return err
877+
}
878+
fmt.Fprintf(out, "Allocated resources (total requests):\n")
879+
for reqResource, reqValue := range reqs {
880+
fmt.Fprintf(out, " %s:\t%s\n", reqResource, reqValue.String())
881+
}
882+
fmt.Fprintf(out, " pods:\t%d\n", len(runningPods))
883+
873884
fmt.Fprintf(out, "Version:\n")
874885
fmt.Fprintf(out, " Kernel Version:\t%s\n", node.Status.NodeInfo.KernelVersion)
875886
fmt.Fprintf(out, " OS Image:\t%s\n", node.Status.NodeInfo.OsImage)
@@ -918,6 +929,52 @@ func describeNode(node *api.Node, pods []*api.Pod, events *api.EventList) (strin
918929
})
919930
}
920931

932+
func filterNonRunningPods(pods []*api.Pod) []*api.Pod {
933+
if len(pods) == 0 {
934+
return pods
935+
}
936+
result := []*api.Pod{}
937+
for _, pod := range pods {
938+
if pod.Status.Phase == api.PodSucceeded || pod.Status.Phase == api.PodFailed {
939+
continue
940+
}
941+
result = append(result, pod)
942+
}
943+
return result
944+
}
945+
946+
func getPodsTotalRequests(pods []*api.Pod) (map[api.ResourceName]resource.Quantity, error) {
947+
reqs := map[api.ResourceName]resource.Quantity{}
948+
for _, pod := range pods {
949+
podReqs, err := getSinglePodTotalRequests(pod)
950+
if err != nil {
951+
return nil, err
952+
}
953+
for podReqName, podReqValue := range podReqs {
954+
if value, ok := reqs[podReqName]; !ok {
955+
reqs[podReqName] = podReqValue
956+
} else if err = value.Add(podReqValue); err != nil {
957+
return nil, err
958+
}
959+
}
960+
}
961+
return reqs, nil
962+
}
963+
964+
func getSinglePodTotalRequests(pod *api.Pod) (map[api.ResourceName]resource.Quantity, error) {
965+
reqs := map[api.ResourceName]resource.Quantity{}
966+
for _, container := range pod.Spec.Containers {
967+
for name, quantity := range container.Resources.Requests {
968+
if value, ok := reqs[name]; !ok {
969+
reqs[name] = quantity
970+
} else if err := value.Add(quantity); err != nil {
971+
return nil, err
972+
}
973+
}
974+
}
975+
return reqs, nil
976+
}
977+
921978
func DescribeEvents(el *api.EventList, w io.Writer) {
922979
if len(el.Items) == 0 {
923980
fmt.Fprint(w, "No events.")

pkg/kubectl/describe_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,78 @@ func TestDefaultDescribers(t *testing.T) {
336336
t.Errorf("unexpected output: %s", out)
337337
}
338338
}
339+
340+
func TestGetPodsTotalRequests(t *testing.T) {
341+
testCases := []struct {
342+
pods []*api.Pod
343+
expectedReqs map[api.ResourceName]resource.Quantity
344+
}{
345+
{
346+
pods: []*api.Pod{
347+
{
348+
Spec: api.PodSpec{
349+
Containers: []api.Container{
350+
{
351+
Resources: api.ResourceRequirements{
352+
Requests: api.ResourceList{
353+
api.ResourceName(api.ResourceCPU): resource.MustParse("1"),
354+
api.ResourceName(api.ResourceMemory): resource.MustParse("300Mi"),
355+
api.ResourceName(api.ResourceStorage): resource.MustParse("1G"),
356+
},
357+
},
358+
},
359+
{
360+
Resources: api.ResourceRequirements{
361+
Requests: api.ResourceList{
362+
api.ResourceName(api.ResourceCPU): resource.MustParse("90m"),
363+
api.ResourceName(api.ResourceMemory): resource.MustParse("120Mi"),
364+
api.ResourceName(api.ResourceStorage): resource.MustParse("200M"),
365+
},
366+
},
367+
},
368+
},
369+
},
370+
},
371+
{
372+
Spec: api.PodSpec{
373+
Containers: []api.Container{
374+
{
375+
Resources: api.ResourceRequirements{
376+
Requests: api.ResourceList{
377+
api.ResourceName(api.ResourceCPU): resource.MustParse("60m"),
378+
api.ResourceName(api.ResourceMemory): resource.MustParse("43Mi"),
379+
api.ResourceName(api.ResourceStorage): resource.MustParse("500M"),
380+
},
381+
},
382+
},
383+
{
384+
Resources: api.ResourceRequirements{
385+
Requests: api.ResourceList{
386+
api.ResourceName(api.ResourceCPU): resource.MustParse("34m"),
387+
api.ResourceName(api.ResourceMemory): resource.MustParse("83Mi"),
388+
api.ResourceName(api.ResourceStorage): resource.MustParse("700M"),
389+
},
390+
},
391+
},
392+
},
393+
},
394+
},
395+
},
396+
expectedReqs: map[api.ResourceName]resource.Quantity{
397+
api.ResourceName(api.ResourceCPU): resource.MustParse("1.184"),
398+
api.ResourceName(api.ResourceMemory): resource.MustParse("546Mi"),
399+
api.ResourceName(api.ResourceStorage): resource.MustParse("2.4G"),
400+
},
401+
},
402+
}
403+
404+
for _, testCase := range testCases {
405+
reqs, err := getPodsTotalRequests(testCase.pods)
406+
if err != nil {
407+
t.Errorf("Unexpected error %v", err)
408+
}
409+
if !reflect.DeepEqual(reqs, testCase.expectedReqs) {
410+
t.Errorf("Expected %v, got %v", testCase.expectedReqs, reqs)
411+
}
412+
}
413+
}

0 commit comments

Comments
 (0)