From 82374eabf5efca1ca91cdb356a0239f7e3caaad9 Mon Sep 17 00:00:00 2001 From: Dylan Verstraete Date: Thu, 26 Nov 2020 11:14:19 +0100 Subject: [PATCH] Zui 80x24 (#1052) * Staging rewrite of zui for 80x24 fixed size * zui: fix panic * use real values for cpu / mem usage, hide storage table * remove wait for capacityd to start zui * aggregate cpu values in zui * fix cpu percentage * refactor cpu rendering * fix types * fix cpu monitor Co-authored-by: Maxime Daniel Co-authored-by: Muhamad Azamy --- cmds/zui/cpu.go | 68 --------------------------- cmds/zui/disk.go | 1 + cmds/zui/header.go | 18 ++++---- cmds/zui/main.go | 79 ++++++-------------------------- cmds/zui/net.go | 55 ++++------------------ cmds/zui/prov.go | 51 +++++++++++++++------ etc/zinit/zui.yaml | 1 - pkg/monitor.go | 5 +- pkg/monitord/system.go | 22 ++++----- pkg/stubs/system_monitor_stub.go | 7 +-- 10 files changed, 86 insertions(+), 221 deletions(-) delete mode 100644 cmds/zui/cpu.go diff --git a/cmds/zui/cpu.go b/cmds/zui/cpu.go deleted file mode 100644 index 48d557075..000000000 --- a/cmds/zui/cpu.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "context" - "fmt" - - ui "github.com/gizak/termui/v3" - "github.com/gizak/termui/v3/widgets" - "github.com/pkg/errors" - "github.com/threefoldtech/zbus" - "github.com/threefoldtech/zos/pkg/stubs" -) - -func cpuRender(client zbus.Client, grid *ui.Grid, render *Flag) error { - const ( - rows = 8 - cols = 20 - ) - - view := widgets.NewTable() - view.Title = "CPU Percentage Per Core" - view.FillRow = true - view.TextStyle.Modifier = ui.ModifierBold - view.RowSeparator = false - view.TextAlignment = ui.AlignCenter - - view.Rows = func() [][]string { - rows := make([][]string, rows) - for i := 0; i < len(rows); i++ { - rows[i] = make([]string, cols) - } - - return rows - }() - - grid.Set( - ui.NewRow(1, - ui.NewCol(1, view), - ), - ) - - monitor := stubs.NewSystemMonitorStub(client) - stream, err := monitor.CPU(context.Background()) - if err != nil { - return errors.Wrap(err, "failed to start cpu monitor stream") - } - - go func() { - for point := range stream { - view.Mutex.Lock() - for i, cpu := range point { - r := i / rows - c := i % rows - if r >= rows || c >= cols { - // no enough space to show this CPU - continue - } - - view.Rows[r][c] = fmt.Sprintf("%0.00f%%", cpu.Percent) - } - view.Mutex.Unlock() - - render.Signal() - } - }() - - return nil -} diff --git a/cmds/zui/disk.go b/cmds/zui/disk.go index a6c1ec2b1..c61f0d5be 100644 --- a/cmds/zui/disk.go +++ b/cmds/zui/disk.go @@ -20,6 +20,7 @@ func diskRender(client zbus.Client, grid *ui.Grid, render *Flag) error { pools := widgets.NewTable() pools.Title = "Storage Pools" pools.RowSeparator = false + pools.TextAlignment = ui.AlignCenter pools.Rows = [][]string{ {"POOL", "TOTAL", "USED"}, } diff --git a/cmds/zui/header.go b/cmds/zui/header.go index c4aa446dc..41e9b3fff 100644 --- a/cmds/zui/header.go +++ b/cmds/zui/header.go @@ -11,6 +11,7 @@ import ( "github.com/threefoldtech/zos/pkg/stubs" ) +// func headerRenderer(c zbus.Client, h *widgets.Paragraph, r *Flag) error { func headerRenderer(c zbus.Client, h *widgets.Paragraph, r *Flag) error { env, err := environment.Get() if err != nil { @@ -22,14 +23,18 @@ func headerRenderer(c zbus.Client, h *widgets.Paragraph, r *Flag) error { var farm string farmID, err := identity.FarmID() if err != nil { - farm = "not attached to a farm" + farm = "not set" } else { farm = fmt.Sprintf("%d", farmID) } - format := fmt.Sprintf("Zero OS [%s] Version: %%s NodeID: %s FarmID: %s", env.RunningMode.String(), nodeID.Identity(), farm) + h.Text = "\n Fetching realtime node information... please wait." - h.Text = "Zero OS" + var s string + s = " Welcome to [Zero-OS](fg:yellow), [ThreeFold](fg:blue) Autonomous Operating System\n" + + "\n" + + " This is node [%s](fg:green) (farmer [%s](fg:green))\n" + + " running Zero-OS version [%s](fg:blue) (mode [%s](fg:cyan))" host := stubs.NewVersionMonitorStub(c) ctx := context.Background() @@ -40,11 +45,8 @@ func headerRenderer(c zbus.Client, h *widgets.Paragraph, r *Flag) error { go func() { for version := range ch { - v := fmt.Sprintf(format, version.String()) - if h.Text != v { - h.Text = v - r.Signal() - } + h.Text = fmt.Sprintf(s, nodeID, farm, version.String(), env.RunningMode.String()) + r.Signal() } }() diff --git a/cmds/zui/main.go b/cmds/zui/main.go index 6d804d5cf..c5b0b7f75 100644 --- a/cmds/zui/main.go +++ b/cmds/zui/main.go @@ -60,78 +60,28 @@ func main() { defer ui.Close() - width, height := ui.TerminalDimensions() - header := widgets.NewParagraph() - header.Border = false - grid := ui.NewGrid() - - headerHeight := 3 - header.SetRect(0, -1, width, headerHeight) - //header.Text = "ZeroOS" - header.TextStyle = ui.Style{ - Fg: ui.ColorBlue, - Bg: ui.ColorClear, - Modifier: ui.ModifierBold, - } - grid.Title = "System" - - grid.SetRect(0, headerHeight-2, width, height) - - cpu := ui.NewGrid() - cpu.Title = "CPU" - cpu.Border = true + width, _ := ui.TerminalDimensions() - mem := ui.NewGrid() - mem.Title = "Memory" - mem.Border = true - - net := ui.NewGrid() - net.Title = "Network" - net.Border = true + header := widgets.NewParagraph() + header.Border = true + header.SetRect(0, 0, width, 6) - disk := ui.NewGrid() - disk.Title = "Disk" - disk.Border = true + netgrid := ui.NewGrid() + netgrid.Title = "Network" + netgrid.SetRect(0, 6, width, 12) provision := ui.NewGrid() - // split in 10 parts - cell := ui.NewGrid() - - cell.Set( - ui.NewRow(4.5/6, disk), - ui.NewRow(1.5/6, provision), - ) - - grid.Set( - ui.NewRow(2.0/10, - ui.NewCol(1, cpu), - ), - ui.NewRow(1.0/10, - ui.NewCol(1, mem), - ), - ui.NewRow(7.0/10, - ui.NewCol(1.0/2, net), - ui.NewCol(1.0/2, cell), - ), - ) + provision.Title = "Provision" + provision.SetRect(0, 12, width, 18) + provision.Border = false var flag Flag if err := headerRenderer(client, header, &flag); err != nil { log.Error().Err(err).Msg("failed to start header renderer") } - if err := cpuRender(client, cpu, &flag); err != nil { - log.Error().Err(err).Msg("failed to start cpu renderer") - } - if err := memRender(client, mem, &flag); err != nil { - log.Error().Err(err).Msg("failed to start mem renderer") - } - - if err := netRender(client, net, &flag); err != nil { - log.Error().Err(err).Msg("failed to start net renderer") - } - if err := diskRender(client, disk, &flag); err != nil { + if err := netRender(client, netgrid, &flag); err != nil { log.Error().Err(err).Msg("failed to start net renderer") } @@ -140,10 +90,9 @@ func main() { } render := func() { - ui.Render(header, grid) + ui.Render(header, netgrid, provision) } - ui.Clear() render() uiEvents := ui.PollEvents() @@ -155,8 +104,8 @@ func main() { return case "": payload := e.Payload.(ui.Resize) - header.SetRect(0, 0, payload.Width, headerHeight) - grid.SetRect(0, headerHeight, payload.Width, payload.Height-headerHeight) + header.SetRect(0, 0, payload.Width, 3) + // grid.SetRect(0, 3, payload.Width, payload.Height) ui.Clear() render() } diff --git a/cmds/zui/net.go b/cmds/zui/net.go index b91e3e75e..2b6ea9607 100644 --- a/cmds/zui/net.go +++ b/cmds/zui/net.go @@ -2,27 +2,27 @@ package main import ( "context" - "fmt" + _ "fmt" "strings" ui "github.com/gizak/termui/v3" "github.com/gizak/termui/v3/widgets" - "github.com/pkg/errors" + _ "github.com/pkg/errors" "github.com/threefoldtech/zbus" "github.com/threefoldtech/zos/pkg" "github.com/threefoldtech/zos/pkg/stubs" ) func addressRender(ctx context.Context, table *widgets.Table, client zbus.Client, render *Flag) error { - table.Title = "Addresses" + table.Title = "Network" table.FillRow = true table.RowSeparator = false table.Rows = [][]string{ - {"ZOS", "Not Configured"}, - {"DMZ", "Not Configured"}, - {"Ygg", "Not Configured"}, - {"Public", "Not Configured"}, + {"ZOS", "Not configured"}, + {"DMZ", "Not configured"}, + {"YGG", "Not configured"}, + {"PUB", "Not configured"}, } stub := stubs.NewNetworkerStub(client) @@ -82,56 +82,17 @@ func addressRender(ctx context.Context, table *widgets.Table, client zbus.Client func netRender(client zbus.Client, grid *ui.Grid, render *Flag) error { addresses := widgets.NewTable() - statistics := widgets.NewTable() - - statistics.Title = "Traffic" - statistics.RowSeparator = false - statistics.Rows = [][]string{ - {"NIC", "SENT", "RECV"}, - } grid.Set( - ui.NewRow(1./6, + ui.NewRow(1, ui.NewCol(1, addresses), ), - ui.NewRow(5.0/6, - ui.NewCol(1, statistics), - ), ) - ctx := context.Background() if err := addressRender(ctx, addresses, client, render); err != nil { return err } - monitor := stubs.NewSystemMonitorStub(client) - stats, err := monitor.Nics(ctx) - if err != nil { - return errors.Wrap(err, "failed to start net monitor stream") - } - - go func() { - for s := range stats { - // keep the header - rows := statistics.Rows[:1] - for _, nic := range s { - if nic.Name == "lo" { - continue - } - rows = append(rows, - []string{ - nic.Name, - fmt.Sprintf("%d KB", nic.RateOut/1024), - fmt.Sprintf("%d KB", nic.RateIn/1024), - }, - ) - } - - statistics.Rows = rows - render.Signal() - } - }() - return nil } diff --git a/cmds/zui/prov.go b/cmds/zui/prov.go index 41bccd70b..7e08f7ca0 100644 --- a/cmds/zui/prov.go +++ b/cmds/zui/prov.go @@ -12,18 +12,15 @@ import ( ) func provisionRender(client zbus.Client, grid *ui.Grid, render *Flag) error { - prov := widgets.NewTable() - prov.Title = "Workloads" + prov.Title = "System Load" prov.RowSeparator = false prov.Rows = [][]string{ - {"Containers", ""}, - {"Volumes", ""}, - {"Networks", ""}, - {"VMs", ""}, - {"ZDB Namespaces", ""}, - {"Debug", ""}, + {"CPU Usage", "", "Memory Usage", ""}, + {"Containers", "", "Volumes", ""}, + {"Networks", "", "VMs", ""}, + {"ZDB NS", "", "Debug", ""}, } grid.Set( @@ -43,13 +40,41 @@ func provisionRender(client zbus.Client, grid *ui.Grid, render *Flag) error { go func() { for counter := range counters { rows := prov.Rows - rows[0][1] = fmt.Sprint(counter.Container) - rows[1][1] = fmt.Sprint(counter.Volume) + rows[1][1] = fmt.Sprint(counter.Container) + rows[1][3] = fmt.Sprint(counter.Volume) rows[2][1] = fmt.Sprint(counter.Network) - rows[3][1] = fmt.Sprint(counter.VM) - rows[4][1] = fmt.Sprint(counter.ZDB) - rows[5][1] = fmt.Sprint(counter.Debug) + rows[2][3] = fmt.Sprint(counter.VM) + rows[3][1] = fmt.Sprint(counter.ZDB) + rows[3][3] = fmt.Sprint(counter.Debug) + + render.Signal() + } + }() + sysMonitor := stubs.NewSystemMonitorStub(client) + stream, err := sysMonitor.CPU(context.Background()) + if err != nil { + return errors.Wrap(err, "failed to start cpu monitor stream") + } + + go func() { + for point := range stream { + prov.Mutex.Lock() + prov.Rows[0][1] = fmt.Sprintf("%0.00f%%", point.Percent) + render.Signal() + prov.Mutex.Unlock() + } + }() + + memoryMonitor := stubs.NewSystemMonitorStub(client) + memStream, err := memoryMonitor.Memory(context.Background()) + if err != nil { + return errors.Wrap(err, "failed to start mem monitor stream") + } + + go func() { + for point := range memStream { + prov.Rows[0][3] = fmt.Sprintf("%0.00f%%", point.UsedPercent) render.Signal() } }() diff --git a/etc/zinit/zui.yaml b/etc/zinit/zui.yaml index 740826e2c..5a6a1de0c 100644 --- a/etc/zinit/zui.yaml +++ b/etc/zinit/zui.yaml @@ -4,5 +4,4 @@ # to it's children. exec: sh -c 'pkill zui; openvt -s -c 3 -w -- zui -broker unix:///var/run/redis.sock' after: - - capacityd - quiet diff --git a/pkg/monitor.go b/pkg/monitor.go index 1b6baab44..43120ad8c 100644 --- a/pkg/monitor.go +++ b/pkg/monitor.go @@ -47,9 +47,6 @@ func (s *TimesStat) String() string { s.CPU, s.Percent, s.User, s.System, s.Idle) } -// CPUTimesStat alias for []TimesStat required by zbus -type CPUTimesStat []TimesStat - // DisksIOCountersStat alias for map[string]IOCountersStat required by zbus type DisksIOCountersStat map[string]DiskIOCountersStat @@ -82,7 +79,7 @@ type PoolsStats map[string]PoolStats //SystemMonitor interface (provided by monitord) type SystemMonitor interface { Memory(ctx context.Context) <-chan VirtualMemoryStat - CPU(ctx context.Context) <-chan CPUTimesStat + CPU(ctx context.Context) <-chan TimesStat Disks(ctx context.Context) <-chan DisksIOCountersStat Nics(ctx context.Context) <-chan NicsIOCounterStat } diff --git a/pkg/monitord/system.go b/pkg/monitord/system.go index 1bf8cd582..7abe919bf 100644 --- a/pkg/monitord/system.go +++ b/pkg/monitord/system.go @@ -60,8 +60,8 @@ func (m *systemMonitor) Memory(ctx context.Context) <-chan pkg.VirtualMemoryStat } // CPU starts cpu monitor stream -func (m *systemMonitor) CPU(ctx context.Context) <-chan pkg.CPUTimesStat { - ch := make(chan pkg.CPUTimesStat) +func (m *systemMonitor) CPU(ctx context.Context) <-chan pkg.TimesStat { + ch := make(chan pkg.TimesStat) go func() { defer close(ch) @@ -70,25 +70,23 @@ func (m *systemMonitor) CPU(ctx context.Context) <-chan pkg.CPUTimesStat { case <-ctx.Done(): return case <-time.After(m.duration): - percents, err := cpu.PercentWithContext(ctx, 0, true) + percents, err := cpu.PercentWithContext(ctx, 0, false) if err != nil { log.Error().Err(err).Msg("failed to read cpu usage percentage") continue } - var result []pkg.TimesStat - now := time.Now() - times, err := cpu.Times(true) + times, err := cpu.Times(false) if err != nil { log.Error().Err(err).Msg("failed to read cpu usage times") continue } - for i, time := range times { - result = append(result, pkg.TimesStat{ - TimesStat: time, - Percent: percents[i], - Time: now, - }) + + result := pkg.TimesStat{ + TimesStat: times[0], + Percent: percents[0], + Time: time.Now(), } + select { case ch <- result: case <-ctx.Done(): diff --git a/pkg/stubs/system_monitor_stub.go b/pkg/stubs/system_monitor_stub.go index 58c01942b..98e5327b5 100644 --- a/pkg/stubs/system_monitor_stub.go +++ b/pkg/stubs/system_monitor_stub.go @@ -2,6 +2,7 @@ package stubs import ( "context" + zbus "github.com/threefoldtech/zbus" pkg "github.com/threefoldtech/zos/pkg" ) @@ -23,8 +24,8 @@ func NewSystemMonitorStub(client zbus.Client) *SystemMonitorStub { } } -func (s *SystemMonitorStub) CPU(ctx context.Context) (<-chan pkg.CPUTimesStat, error) { - ch := make(chan pkg.CPUTimesStat) +func (s *SystemMonitorStub) CPU(ctx context.Context) (<-chan pkg.TimesStat, error) { + ch := make(chan pkg.TimesStat) recv, err := s.client.Stream(ctx, s.module, s.object, "CPU") if err != nil { return nil, err @@ -32,7 +33,7 @@ func (s *SystemMonitorStub) CPU(ctx context.Context) (<-chan pkg.CPUTimesStat, e go func() { defer close(ch) for event := range recv { - var obj pkg.CPUTimesStat + var obj pkg.TimesStat if err := event.Unmarshal(&obj); err != nil { panic(err) }