Skip to content

Commit

Permalink
Merge pull request #610 from cvaroqui/main
Browse files Browse the repository at this point in the history
tui
  • Loading branch information
cgalibern authored Oct 25, 2024
2 parents d0eb85c + 4b4258c commit 4e63cd3
Show file tree
Hide file tree
Showing 35 changed files with 3,683 additions and 376 deletions.
22 changes: 12 additions & 10 deletions core/monitor/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,29 @@ var (
"objects": sectionObjects,
"services": sectionObjects,
}
green, yellow, red, blue, hiblue, hiblack, bold func(a ...interface{}) string
green, yellow, hired, red, blue, hiblue, hiblack, bold func(a ...interface{}) string
iconUp, iconWarning, iconDownIssue, iconPlacementAlert, iconProvisionAlert, iconStandbyDown, iconStandbyUpIssue, iconUndef, iconFrozen, iconDown, iconDRP, iconLeader, iconNotApplicable, iconPreserved, iconStandbyUp string
)

func initColor() {
func InitColor() {
green = color.New(color.FgGreen).SprintFunc()
yellow = color.New(color.FgYellow).SprintFunc()
red = color.New(color.FgRed).SprintFunc()
hired = color.New(color.FgHiRed).SprintFunc()
blue = color.New(color.FgBlue).SprintFunc()
hiblue = color.New(color.FgHiBlue).SprintFunc()
hiblack = color.New(color.FgHiBlack).SprintFunc()
bold = color.New(color.Bold).SprintFunc()

iconUp = green("O")
iconWarning = yellow("!")
iconDownIssue = red("X")
iconPlacementAlert = red("^")
iconProvisionAlert = red("P")
iconStandbyDown = red("x")
iconStandbyUpIssue = red("o")
iconUndef = red("?")
iconFrozen = blue("*")
iconDownIssue = hired("X")
iconPlacementAlert = hired("^")
iconProvisionAlert = hired("P")
iconStandbyDown = hired("x")
iconStandbyUpIssue = hired("o")
iconUndef = hired("?")
iconFrozen = hiblue("*")
iconDown = hiblack("X")
iconDRP = hiblack("#")
iconLeader = hiblack("^")
Expand Down Expand Up @@ -103,11 +104,12 @@ func (f Frame) hasSection(section string) bool {
// representation of Render.
func (f *Frame) Render() string {
var builder strings.Builder
initColor()
InitColor()

green = color.New(color.FgGreen).SprintFunc()
yellow = color.New(color.FgYellow).SprintFunc()
red = color.New(color.FgRed).SprintFunc()
hired = color.New(color.FgHiRed).SprintFunc()
blue = color.New(color.FgBlue).SprintFunc()
hiblue = color.New(color.FgHiBlue).SprintFunc()
hiblack = color.New(color.FgHiBlack).SprintFunc()
Expand Down
4 changes: 2 additions & 2 deletions core/monitor/frame_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/opensvc/om3/core/status"
)

func (f Frame) sObjectInstance(path string, node string, scope []string) string {
func (f Frame) StrObjectInstance(path string, node string, scope []string) string {
s := ""
avail := f.Current.Cluster.Object[path].Avail
inst := f.Current.Cluster.Node[node].Instance[path]
Expand Down Expand Up @@ -37,7 +37,7 @@ func (f Frame) sObjectInstance(path string, node string, scope []string) string
} else if inst.Config != nil || slices.Contains(scope, node) {
s += iconUndef
}
return s + "\t"
return s
}

func sObjectInstanceAvail(objectAvail status.T, instance instance.Status, mon instance.Monitor) string {
Expand Down
42 changes: 23 additions & 19 deletions core/monitor/frame_nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,45 @@ import (
func (f Frame) sNodeScoreLine() string {
s := fmt.Sprintf(" %s\t\t\t%s\t", bold("score"), f.info.separator)
for _, n := range f.Current.Cluster.Config.Nodes {
s += f.sNodeScore(n) + "\t"
s += f.StrNodeScore(n) + "\t"
}
return s
}
func (f Frame) sNodeLoadLine() string {
s := fmt.Sprintf(" %s\t\t\t%s\t", bold("load15m"), f.info.separator)
for _, n := range f.Current.Cluster.Config.Nodes {
s += f.sNodeLoad(n) + "\t"
s += f.StrNodeLoad(n) + "\t"
}
return s
}

func (f Frame) sNodeMemLine() string {
s := fmt.Sprintf(" %s\t\t\t%s\t", bold("mem"), f.info.separator)
for _, n := range f.Current.Cluster.Config.Nodes {
s += f.sNodeMem(n) + "\t"
s += f.StrNodeMem(n) + "\t"
}
return s
}

func (f Frame) sNodeSwapLine() string {
s := fmt.Sprintf(" %s\t\t\t%s\t", bold("swap"), f.info.separator)
for _, n := range f.Current.Cluster.Config.Nodes {
s += f.sNodeSwap(n) + "\t"
s += f.StrNodeSwap(n) + "\t"
}
return s
}

func (f Frame) StrNodeStates(n string) string {
s := f.sNodeMonState(n)
s += f.sNodeFrozen(n)
s += f.sNodeMonTarget(n)
return s
}

func (f Frame) sNodeWarningsLine() string {
s := fmt.Sprintf(" %s\t\t\t%s\t", bold("state"), f.info.separator)
for _, n := range f.Current.Cluster.Config.Nodes {
s += f.sNodeMonState(n)
s += f.sNodeFrozen(n)
s += f.sNodeMonTarget(n)
s += "\t"
s += f.StrNodeStates(n) + "\t"
}
return s
}
Expand Down Expand Up @@ -78,21 +82,21 @@ func (f Frame) sNodeCompatLine() string {
return s + "\n"
}

func (f Frame) sNodeScore(n string) string {
func (f Frame) StrNodeScore(n string) string {
if val, ok := f.Current.Cluster.Node[n]; ok {
return fmt.Sprintf("%d", val.Stats.Score)
}
return iconUndef
}

func (f Frame) sNodeLoad(n string) string {
func (f Frame) StrNodeLoad(n string) string {
if val, ok := f.Current.Cluster.Node[n]; ok {
return fmt.Sprintf("%.1f", val.Stats.Load15M)
}
return iconUndef
}

func (f Frame) sNodeMem(n string) string {
func (f Frame) StrNodeMem(n string) string {
if val, ok := f.Current.Cluster.Node[n]; ok {
if val.Stats.MemTotalMB == 0 {
return hiblue("-")
Expand All @@ -105,19 +109,19 @@ func (f Frame) sNodeMem(n string) string {
total := sizeconv.BSizeCompactFromMB(val.Stats.MemTotalMB)
var s string
if limit > 0 {
s = fmt.Sprintf("%d/%d%%:%s", usage, limit, total)
s = fmt.Sprintf("%d%%%s<%d%%", usage, total, limit)
} else {
s = fmt.Sprintf("%d%%:%s", usage, total)
s = fmt.Sprintf("%d%%%s", usage, total)
}
if usage > limit {
return red(s)
return hired(s)
}
return s
}
return iconUndef
}

func (f Frame) sNodeSwap(n string) string {
func (f Frame) StrNodeSwap(n string) string {
if val, ok := f.Current.Cluster.Node[n]; ok {
if val.Stats.SwapTotalMB == 0 {
return hiblue("-")
Expand All @@ -130,12 +134,12 @@ func (f Frame) sNodeSwap(n string) string {
total := sizeconv.BSizeCompactFromMB(val.Stats.SwapTotalMB)
var s string
if limit > 0 {
s = fmt.Sprintf("%d/%d%%:%s", usage, limit, total)
s = fmt.Sprintf("%d%%%s<%d%%", usage, total, limit)
} else {
s = fmt.Sprintf("%d%%:%s", usage, total)
s = fmt.Sprintf("%d%%%s", usage, total)
}
if usage > limit {
return red(s)
return hired(s)
}
return s
}
Expand Down Expand Up @@ -220,7 +224,7 @@ func (f Frame) sNodeHbMode() string {
}
case "":
if nodeCount > 1 {
mode = red("?")
mode = hired("?")
} else {
mode = "?"
}
Expand Down
24 changes: 16 additions & 8 deletions core/monitor/frame_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ func (f Frame) scalerInstancesUp(path string) int {
return actual
}

func (f Frame) sObjectRunning(path string) string {
func (f Frame) sObjectOrchestrateAndRunning(path string) string {
s := f.Current.Cluster.Object[path]
return fmt.Sprintf("%-5s %s", s.Orchestrate, f.StrObjectRunning(path))
}

func (f Frame) StrObjectRunning(path string) string {
var (
actual, expected int
)
Expand Down Expand Up @@ -92,28 +97,31 @@ func (f Frame) sObjectRunning(path string) string {
case actual == 0 && expected == 0:
return ""
case expected == 0:
return fmt.Sprintf("%-5s %d", s.Orchestrate, actual)
return fmt.Sprintf("%d", actual)
case avail == status.NotApplicable:
return fmt.Sprintf("%-5s", s.Orchestrate)
return ""
default:
return fmt.Sprintf("%-5s %d/%d", s.Orchestrate, actual, expected)
return fmt.Sprintf("%d/%d", actual, expected)
}
}

func StrObjectStatus(d object.Status) string {
return sObjectAvail(d) + sObjectWarning(d) + sObjectPlacement(d)
}

func sObjectAvail(d object.Status) string {
s := d.Avail
return colorstatus.Sprint(s, rawconfig.Colorize)
}

func (f Frame) sObject(path string) string {
d := f.Current.Cluster.Object[path]
c3 := sObjectAvail(d) + sObjectWarning(d) + sObjectPlacement(d)
s := fmt.Sprintf(" %s\t", bold(path))
s += fmt.Sprintf("%s\t", c3)
s += fmt.Sprintf("%s\t", f.sObjectRunning(path))
s += fmt.Sprintf("%s\t", StrObjectStatus(d))
s += fmt.Sprintf("%s\t", f.sObjectOrchestrateAndRunning(path))
s += fmt.Sprintf("%s\t", f.info.separator)
for _, node := range f.Current.Cluster.Config.Nodes {
s += f.sObjectInstance(path, node, d.Scope)
s += f.StrObjectInstance(path, node, d.Scope) + "\t"
}
return s
}
6 changes: 3 additions & 3 deletions core/monitor/frame_threads.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ func (f Frame) wThreadHeartbeats() string {
case "running":
s += green("running") + sThreadAlerts(hbStatus.Alerts)
case "stopped":
s += red("stopped") + sThreadAlerts(hbStatus.Alerts)
s += hired("stopped") + sThreadAlerts(hbStatus.Alerts)
case "failed":
s += red("failed") + sThreadAlerts(hbStatus.Alerts)
s += hired("failed") + sThreadAlerts(hbStatus.Alerts)
default:
s += red("unknown") + sThreadAlerts(hbStatus.Alerts)
s += hired("unknown") + sThreadAlerts(hbStatus.Alerts)
}
s += "\t" + hbStatus.Type + "\t"
s += f.info.separator + "\t"
Expand Down
4 changes: 2 additions & 2 deletions core/monitor/testdata/multi-node-om-mon.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ Threads node1 node2 node3
Nodes node1 node2 node3
score | 95 96 96
load15m | 0.1 0.2 0.1
mem | 27/100%:1.94g 24/100%:1.94g 26/100%:1.94g
swap | 2/100%:1.92g 0/100%:1.92g 1/100%:1.92g
mem | 27%1.94g<100% 24%1.94g<100% 26%1.94g<100%
swap | 2%1.92g<100% 0%1.92g<100% 1%1.92g<100%
hb-q | 1 0 0
state |

Expand Down
4 changes: 2 additions & 2 deletions core/monitor/testdata/single-node-om-mon.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Threads node3
Nodes node3
score | 96
load15m | 0.1
mem | 26/100%:1.94g
swap | 0/100%:1.92g
mem | 26%1.94g<100%
swap | 0%1.92g<100%
compat warn | 12
state | *

Expand Down
9 changes: 7 additions & 2 deletions core/object/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ func WithConfigFile(s string) funcopt.O {
// Useful for testing volatile services.
func WithConfigData(b any) funcopt.O {
return funcopt.F(func(t any) error {
o := t.(*core)
o.configData = b
if o, ok := t.(*core); ok {
o.configData = b
} else if o, ok := t.(*Node); ok {
o.configData = b
} else {
return fmt.Errorf("WithConfigData() is not supported on %v", t)
}
return nil
})
}
Expand Down
1 change: 1 addition & 0 deletions core/object/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type (

// caches
id uuid.UUID
configData any
configFile string
config *xconfig.T
mergedConfig *xconfig.T
Expand Down
13 changes: 11 additions & 2 deletions core/object/node_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,24 @@ func (t *Node) ClusterConfigFile() string {
}

func (t *Node) loadConfig() error {
var sources []any
nodeConfigFile := t.ConfigFile()
if config, err := xconfig.NewObject(nodeConfigFile, nodeConfigFile); err != nil {

if t.configData != nil {
sources = []any{t.configData}
} else {
sources = []any{nodeConfigFile}
}

if config, err := xconfig.NewObject(nodeConfigFile, sources...); err != nil {
return err
} else {
t.config = config
t.config.Referrer = t
}
clusterConfigFile := t.ClusterConfigFile()
if config, err := xconfig.NewObject(clusterConfigFile, clusterConfigFile, nodeConfigFile); err != nil {
sources = append([]any{clusterConfigFile}, sources...)
if config, err := xconfig.NewObject(clusterConfigFile, sources...); err != nil {
return err
} else {
t.mergedConfig = config
Expand Down
7 changes: 7 additions & 0 deletions core/object/node_keywords.go
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,13 @@ var nodeCommonKeywords = []keywords.Keyword{
Text: keywords.NewText(fs, "text/kw/node/pool.vg.name"),
Types: []string{"vg"},
},
{
DefaultText: keywords.NewText(fs, "text/kw/node/pool.drbd.addr.default"),
Example: "1.2.3.4",
Option: "addr",
Scopable: true,
Text: keywords.NewText(fs, "text/kw/node/pool.drbd.addr"),
},
{
Option: "vg",
Section: "pool",
Expand Down
2 changes: 2 additions & 0 deletions core/object/text/kw/node/pool.drbd.addr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The addr to use to connect a peer. Use scoping to define each non-default
address.
1 change: 1 addition & 0 deletions core/object/text/kw/node/pool.drbd.addr.default
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The ipaddr resolved for the nodename.
4 changes: 4 additions & 0 deletions core/ox/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/opensvc/om3/core/env"
"github.com/opensvc/om3/core/naming"
"github.com/opensvc/om3/core/rawconfig"
"github.com/opensvc/om3/core/tui"
"github.com/opensvc/om3/util/version"
)

Expand All @@ -35,6 +36,9 @@ var (
ValidArgsFunction: validArgs,
BashCompletionFunction: bashCompletionFunction,
Version: version.Version(),
RunE: func(cmd *cobra.Command, args []string) error {
return tui.Run(args)
},
}
)

Expand Down
Loading

0 comments on commit 4e63cd3

Please sign in to comment.