reworked cpu/mem limits

mine
derailed 2020-01-22 13:42:51 -07:00
parent 995158d446
commit f9e32003b9
9 changed files with 68 additions and 37 deletions

View File

@ -32,7 +32,7 @@ func TestTableReconcile(t *testing.T) {
err := ta.reconcile(ctx)
assert.Nil(t, err)
data := ta.Peek()
assert.Equal(t, 13, len(data.Header))
assert.Equal(t, 15, len(data.Header))
assert.Equal(t, 1, len(data.RowEvents))
assert.Equal(t, client.NamespaceAll, data.Namespace)
}
@ -110,7 +110,7 @@ func TestTableHydrate(t *testing.T) {
assert.Nil(t, hydrate("blee", oo, rr, render.Pod{}))
assert.Equal(t, 1, len(rr))
assert.Equal(t, 12, len(rr[0].Fields))
assert.Equal(t, 14, len(rr[0].Fields))
}
func TestTableGenericHydrate(t *testing.T) {

View File

@ -32,7 +32,7 @@ func TestTableRefresh(t *testing.T) {
ctx = context.WithValue(ctx, internal.KeyFields, "")
ta.Refresh(ctx)
data := ta.Peek()
assert.Equal(t, 13, len(data.Header))
assert.Equal(t, 15, len(data.Header))
assert.Equal(t, 1, len(data.RowEvents))
assert.Equal(t, client.NamespaceAll, data.Namespace)
assert.Equal(t, 1, l.count)

View File

@ -77,6 +77,8 @@ func (Container) Header(ns string) HeaderRow {
Header{Name: "MEM", Align: tview.AlignRight},
Header{Name: "%CPU", Align: tview.AlignRight},
Header{Name: "%MEM", Align: tview.AlignRight},
Header{Name: "%MAX-CPU", Align: tview.AlignRight},
Header{Name: "%MAX-MEM", Align: tview.AlignRight},
Header{Name: "PORTS"},
Header{Name: "AGE", Decorator: AgeDecorator},
}
@ -89,7 +91,7 @@ func (c Container) Render(o interface{}, name string, r *Row) error {
return fmt.Errorf("Expected ContainerRes, but got %T", o)
}
cur, perc := gatherMetrics(co.Container, co.MX)
cur, perc, limit := gatherMetrics(co.Container, co.MX)
ready, state, restarts := "false", MissingValue, "0"
if co.Status != nil {
ready, state, restarts = boolToStr(co.Status.Ready), toState(co.Status.State), strconv.Itoa(int(co.Status.RestartCount))
@ -109,6 +111,8 @@ func (c Container) Render(o interface{}, name string, r *Row) error {
cur.mem,
perc.cpu,
perc.mem,
limit.cpu,
limit.mem,
toStrPorts(co.Container.Ports),
toAge(co.Age),
)
@ -119,8 +123,8 @@ func (c Container) Render(o interface{}, name string, r *Row) error {
// ----------------------------------------------------------------------------
// Helpers...
func gatherMetrics(co *v1.Container, mx *mv1beta1.ContainerMetrics) (c, p metric) {
c, p = noMetric(), noMetric()
func gatherMetrics(co *v1.Container, mx *mv1beta1.ContainerMetrics) (c, p, l metric) {
c, p, l = noMetric(), noMetric(), noMetric()
if mx == nil {
return
}
@ -140,6 +144,14 @@ func gatherMetrics(co *v1.Container, mx *mv1beta1.ContainerMetrics) (c, p metric
p.mem = AsPerc(toPerc(mem, ToMB(rmem.Value())))
}
lcpu, lmem := containerLimits(*co)
if lcpu != nil {
l.cpu = AsPerc(toPerc(float64(cpu), float64(lcpu.MilliValue())))
}
if lmem != nil {
l.mem = AsPerc(toPerc(mem, ToMB(lmem.Value())))
}
return
}

View File

@ -38,6 +38,8 @@ func TestContainer(t *testing.T) {
"20",
"50",
"20",
"50",
"20",
"",
},
r.Fields[:len(r.Fields)-1],

View File

@ -75,11 +75,13 @@ func (Pod) Header(ns string) HeaderRow {
Header{Name: "NAME"},
Header{Name: "READY"},
Header{Name: "STATUS"},
Header{Name: "RESTART", Align: tview.AlignRight},
Header{Name: "RS", Align: tview.AlignRight},
Header{Name: "CPU", Align: tview.AlignRight},
Header{Name: "MEM", Align: tview.AlignRight},
Header{Name: "%CPU (LIM)", Align: tview.AlignRight},
Header{Name: "%MEM (LIM)", Align: tview.AlignRight},
Header{Name: "%CPU", Align: tview.AlignRight},
Header{Name: "%MEM", Align: tview.AlignRight},
Header{Name: "%MAX_CPU", Align: tview.AlignRight},
Header{Name: "%MAX_MEM", Align: tview.AlignRight},
Header{Name: "IP"},
Header{Name: "NODE"},
Header{Name: "QOS"},
@ -116,8 +118,10 @@ func (p Pod) Render(o interface{}, ns string, r *Row) error {
strconv.Itoa(rc),
c.cpu,
c.mem,
perc.cpu+" ("+fmt.Sprintf("%3v",perc.cpuLim)+")",
perc.mem+" ("+fmt.Sprintf("%3v",perc.memLim)+")",
perc.cpu,
perc.mem,
perc.cpuLim,
perc.memLim,
na(po.Status.PodIP),
na(po.Spec.NodeName),
p.mapQOS(po.Status.QOSClass),
@ -158,11 +162,11 @@ func (*Pod) gatherPodMX(pod *v1.Pod, mx *mv1beta1.PodMetrics) (c, p metric) {
mem: ToMi(ToMB(mem.Value())),
}
rc, rm := requestedRes(pod)
lc, lm := resourceLimits(pod)
rc, rm := requestedRes(pod.Spec.Containers)
lc, lm := resourceLimits(pod.Spec.Containers)
p = metric{
cpu: AsPerc(toPerc(float64(cpu.MilliValue()), float64(rc.MilliValue()))),
mem: AsPerc(toPerc(ToMB(mem.Value()), ToMB(rm.Value()))),
cpu: AsPerc(toPerc(float64(cpu.MilliValue()), float64(rc.MilliValue()))),
mem: AsPerc(toPerc(ToMB(mem.Value()), ToMB(rm.Value()))),
cpuLim: AsPerc(toPerc(float64(cpu.MilliValue()), float64(lc.MilliValue()))),
memLim: AsPerc(toPerc(ToMB(mem.Value()), ToMB(lm.Value()))),
}
@ -172,7 +176,6 @@ func (*Pod) gatherPodMX(pod *v1.Pod, mx *mv1beta1.PodMetrics) (c, p metric) {
func containerResources(co v1.Container) (cpu, mem *resource.Quantity) {
req, limit := co.Resources.Requests, co.Resources.Limits
switch {
case len(req) != 0:
cpu, mem = req.Cpu(), req.Memory()
@ -183,23 +186,32 @@ func containerResources(co v1.Container) (cpu, mem *resource.Quantity) {
return
}
func resourceLimits(po *v1.Pod) (cpu, mem resource.Quantity) {
for _, co := range po.Spec.Containers {
func containerLimits(co v1.Container) (cpu, mem *resource.Quantity) {
limit := co.Resources.Limits
if len(limit) == 0 {
return nil, nil
}
return limit.Cpu(), limit.Memory()
}
func resourceLimits(cc []v1.Container) (cpu, mem resource.Quantity) {
for _, co := range cc {
limit := co.Resources.Limits
if len(limit) != 0 {
if limit.Cpu() != nil {
cpu.Add(*limit.Cpu())
}
if limit.Memory() != nil {
mem.Add(*limit.Memory())
}
if len(limit) == 0 {
continue
}
if limit.Cpu() != nil {
cpu.Add(*limit.Cpu())
}
if limit.Memory() != nil {
mem.Add(*limit.Memory())
}
}
return
}
func requestedRes(po *v1.Pod) (cpu, mem resource.Quantity) {
for _, co := range po.Spec.Containers {
func requestedRes(cc []v1.Container) (cpu, mem resource.Quantity) {
for _, co := range cc {
c, m := containerResources(co)
if c != nil {
cpu.Add(*c)
@ -212,6 +224,9 @@ func requestedRes(po *v1.Pod) (cpu, mem resource.Quantity) {
}
func currentRes(mx *mv1beta1.PodMetrics) (cpu, mem resource.Quantity) {
if mx == nil {
return
}
for _, co := range mx.Containers {
c, m := co.Usage.Cpu(), co.Usage.Memory()
cpu.Add(*c)

View File

@ -65,13 +65,13 @@ func TestPodRender(t *testing.T) {
}
var po render.Pod
r := render.NewRow(12)
r := render.NewRow(14)
err := po.Render(&pom, "", &r)
assert.Nil(t, err)
assert.Equal(t, "default/nginx", r.ID)
e := render.Fields{"default", "nginx", "1/1", "Running", "0", "10", "10", "10 ( 0)", "14 ( 5)", "172.17.0.6", "minikube", "BE"}
assert.Equal(t, e, r.Fields[:12])
e := render.Fields{"default", "nginx", "1/1", "Running", "0", "10", "10", "10", "14", "0", "5", "172.17.0.6", "minikube", "BE"}
assert.Equal(t, e, r.Fields[:14])
}
func BenchmarkPodRender(b *testing.B) {
@ -96,13 +96,13 @@ func TestPodInitRender(t *testing.T) {
}
var po render.Pod
r := render.NewRow(12)
r := render.NewRow(14)
err := po.Render(&pom, "", &r)
assert.Nil(t, err)
assert.Equal(t, "default/nginx", r.ID)
e := render.Fields{"default", "nginx", "1/1", "Init:0/1", "0", "10", "10", "10 ( 0)", "14 ( 5)", "172.17.0.6", "minikube", "BE"}
assert.Equal(t, e, r.Fields[:12])
e := render.Fields{"default", "nginx", "1/1", "Init:0/1", "0", "10", "10", "10", "14", "0", "5", "172.17.0.6", "minikube", "BE"}
assert.Equal(t, e, r.Fields[:14])
}
// ----------------------------------------------------------------------------

View File

@ -21,7 +21,7 @@ func TestHelp(t *testing.T) {
v := view.NewHelp()
assert.Nil(t, v.Init(ctx))
assert.Equal(t, 17, v.GetRowCount())
assert.Equal(t, 19, v.GetRowCount())
assert.Equal(t, 8, v.GetColumnCount())
assert.Equal(t, "<ctrl-k>", strings.TrimSpace(v.GetCell(1, 0).Text))
assert.Equal(t, "Kill", strings.TrimSpace(v.GetCell(1, 1).Text))

View File

@ -48,8 +48,10 @@ func (p *Pod) bindKeys(aa ui.KeyActions) {
ui.KeyShiftM: ui.NewKeyAction("Sort MEM", p.GetTable().SortColCmd(5, false), false),
ui.KeyShiftX: ui.NewKeyAction("Sort CPU%", p.GetTable().SortColCmd(6, false), false),
ui.KeyShiftZ: ui.NewKeyAction("Sort MEM%", p.GetTable().SortColCmd(7, false), false),
ui.KeyShiftI: ui.NewKeyAction("Sort IP", p.GetTable().SortColCmd(8, true), false),
ui.KeyShiftO: ui.NewKeyAction("Sort Node", p.GetTable().SortColCmd(9, true), false),
tcell.KeyCtrlX: ui.NewKeyAction("Sort CPU% LIMITS", p.GetTable().SortColCmd(8, false), false),
tcell.KeyCtrlZ: ui.NewKeyAction("Sort MEM% LIMITS", p.GetTable().SortColCmd(9, false), false),
ui.KeyShiftI: ui.NewKeyAction("Sort IP", p.GetTable().SortColCmd(10, true), false),
ui.KeyShiftO: ui.NewKeyAction("Sort Node", p.GetTable().SortColCmd(11, true), false),
})
}

View File

@ -16,7 +16,7 @@ func TestPodNew(t *testing.T) {
assert.Nil(t, po.Init(makeCtx()))
assert.Equal(t, "Pods", po.Name())
assert.Equal(t, 16, len(po.Hints()))
assert.Equal(t, 18, len(po.Hints()))
}
// Helpers...