diff options
author | matthieu <matthieu.cneude@gmail.com> | 2020-05-29 15:07:03 +0200 |
---|---|---|
committer | matthieu <matthieu.cneude@gmail.com> | 2020-05-29 15:07:03 +0200 |
commit | 83a87f4654e665dc311c46180f21e2e12e85dfe6 (patch) | |
tree | 4281e68eba3c58d6407f229e19e2d2c77dee22e6 | |
parent | 74c6e4afd6f6a734d9a684f4d4ec223d4d70e01c (diff) |
Add possibility to pass any command line or bash script to render it in
your dashboard!!??!!
-rw-r--r-- | go.mod | 1 | ||||
-rw-r--r-- | go.sum | 14 | ||||
-rw-r--r-- | gokit/cmd.go | 48 | ||||
-rw-r--r-- | internal/platform/remote_host.go | 56 | ||||
-rw-r--r-- | internal/remote_host_widget.go | 39 | ||||
-rw-r--r-- | internal/widget.go | 6 |
6 files changed, 132 insertions, 32 deletions
@@ -8,6 +8,7 @@ require ( cloud.google.com/go/storage v1.1.2 // indirect github.com/OneOfOne/xxhash v1.2.5 // indirect github.com/Phantas0s/termui v0.0.0-20190825161953-d204f6ac0873 + github.com/Phantas0s/testomatic v0.2.2 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect github.com/coreos/bbolt v1.3.3 // indirect github.com/coreos/etcd v3.3.17+incompatible // indirect @@ -23,6 +23,8 @@ github.com/Phantas0s/termui v0.0.0-20190825161953-d204f6ac0873 h1:5YLbONHvxijEMs github.com/Phantas0s/termui v0.0.0-20190825161953-d204f6ac0873/go.mod h1:5R72E8oDvxobkryx5DK/lfblYGHe5y0pIWuFdoQOsl8= github.com/Phantas0s/termui v2.3.0+incompatible h1:koWp4DWtxihOl4KIeLBalrZPzn0BC9MkJrtekmVV2H0= github.com/Phantas0s/termui v2.3.0+incompatible/go.mod h1:7yheYfLhXyesNA0CRRq6ue9v3e8EY6XIOf3S0Gv9XIQ= +github.com/Phantas0s/testomatic v0.2.2 h1:P5xOf//fyfak5C1O21Q8El772ScE0LVhcdoMx85xIFA= +github.com/Phantas0s/testomatic v0.2.2/go.mod h1:R/VMPNmiU65Q6k0FUYZN3QdQ/e5QtNtiQuvtRKjQZZk= github.com/Phantas0s/tweetwee v0.0.0-20200113183733-ace5c0dbb457/go.mod h1:zDSbXhR85saU43g9I2cLXGTH28qGofHpD1Hu9XKSkIM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -66,6 +68,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gen2brain/beeep v0.0.0-20190603194150-07ff5e574111 h1:RqBJYx7nqCnDQhJtIy7jrZnJ2pwBRnYhRuVQrrlX3pU= +github.com/gen2brain/beeep v0.0.0-20190603194150-07ff5e574111/go.mod h1:GprdPCZglWh5OMcIDpeKBxuUJI+fEDOTVUfxZeda4zo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gizak/termui v2.3.0+incompatible/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA= github.com/gizak/termui v3.1.0+incompatible/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA= @@ -76,6 +80,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= +github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -113,6 +119,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherwasm v1.1.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -186,6 +194,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317 h1:hhGN4SFXgXo61Q4Sjj/X9sBjyeSa2kdpaOzCO+8EVQw= github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= +github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -217,6 +226,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= +github.com/radovskyb/watcher v1.0.6 h1:8WIQ9UxEYMZjem1OwU7dVH94DXXk9mAIE1i8eqHD+IY= +github.com/radovskyb/watcher v1.0.6/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -265,6 +276,7 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -367,6 +379,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qd golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c h1:S/FtSvpNLtFBgjTqcKsRpsa6aVsI6iztaz1bQd9BJwE= @@ -445,6 +458,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2/go.mod h1:s1Sn2yZos05Qfs7NKt867Xe18emOmtsO3eAKbDaon0o= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/gokit/cmd.go b/gokit/cmd.go new file mode 100644 index 0000000..8899081 --- /dev/null +++ b/gokit/cmd.go @@ -0,0 +1,48 @@ +package gokit + +import ( + "bytes" + "os/exec" + "strings" +) + +func Pipeline(command string) (out, errs []byte, pipeLineError error) { + cmds := []*exec.Cmd{} + piped := strings.Split(command, "|") + for _, v := range piped { + c := strings.Split(strings.TrimSpace(v), " ") + for k, v := range c[1:] { + c[k+1] = strings.Replace(v, "'", "", -1) + } + // let it here for debug purposes... might need it :D + // fmt.Println(c[0]) + // fmt.Println(strings.Join(c[1:], ",")) + cmds = append(cmds, exec.Command(strings.TrimSpace(c[0]), c[1:]...)) + } + + var stderr bytes.Buffer + last := len(cmds) - 1 + for i, cmd := range cmds[:last] { + var err error + if cmds[i+1].Stdin, err = cmd.StdoutPipe(); err != nil { + return nil, nil, err + } + cmd.Stderr = &stderr + } + + var output bytes.Buffer + cmds[last].Stdout, cmds[last].Stderr = &output, &stderr + for _, cmd := range cmds { + if err := cmd.Start(); err != nil { + return output.Bytes(), stderr.Bytes(), err + } + } + + for _, cmd := range cmds { + if err := cmd.Wait(); err != nil { + return output.Bytes(), stderr.Bytes(), err + } + } + + return output.Bytes(), stderr.Bytes(), nil +} diff --git a/internal/platform/remote_host.go b/internal/platform/remote_host.go index 0a243c6..b0f8290 100644 --- a/internal/platform/remote_host.go +++ b/internal/platform/remote_host.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "fmt" - "os/exec" "regexp" "strconv" "strings" @@ -68,20 +67,16 @@ func (s *RemoteHost) run(command string) (string, error) { } func runLocalhost(command string) (string, error) { - c := strings.Split(command, " ") - cmd := exec.Command(c[0], c[1:]...) - - var out bytes.Buffer - cmd.Stdout = &out - - err := cmd.Run() + out, errs, err := gokit.Pipeline(command) if err != nil { return "", err } - result := out.String() + if string(errs) != "" { + return "", errors.New(string(errs)) + } - return result, nil + return string(out), nil } func (s *RemoteHost) Uptime() (int64, error) { @@ -147,24 +142,6 @@ func (s *RemoteHost) Processes() (string, error) { return fmt.Sprintf("%s/%s", runProc, totalProc), nil } -// TODO no need to specify headers -// TODO not used for now - create a table from the return of correctly formatted any command -func (s *RemoteHost) Table(command string, headers []string, metrics []string) (cells [][]string, err error) { - lines, err := s.run(command) - if err != nil { - return nil, err - } - - scanner := bufio.NewScanner(strings.NewReader(lines)) - data := "" - for scanner.Scan() { - line := scanner.Text() - data += line - } - - return formatToTable(headers, data), nil -} - func (s *RemoteHost) Memory(metrics []string, unit string) (val []int, err error) { lines, err := s.run("/bin/cat /proc/meminfo") if err != nil { @@ -362,6 +339,27 @@ func (s *RemoteHost) NetIO(unit string) (string, error) { return rx + " / " + tx, nil } +// TODO no need to specify headers +// TODO not used for now - create a table from the return of correctly formatted any command +func (s *RemoteHost) Table(command string, headers []string) (cells [][]string, err error) { + lines, err := s.run(command) + if err != nil { + return nil, err + } + + scanner := bufio.NewScanner(strings.NewReader(lines)) + data := "" + for scanner.Scan() { + line := scanner.Text() + parts := strings.Fields(line) + + data += strings.Join(parts, ",") + "," + } + data = strings.Trim(data, ",") + + return formatToTable(headers, data), nil +} + func (s *RemoteHost) Disk(headers []string, unit string) ([][]string, error) { // GetIOStat returns io stat lines, err := s.run("/bin/df -x devtmpfs -x tmpfs -x debugfs") @@ -408,6 +406,8 @@ func (s *RemoteHost) Disk(headers []string, unit string) ([][]string, error) { count++ } + data = strings.Trim(data, ",") + c := [][]string{headers} c = append(c, formatToTable(headers, data)...) diff --git a/internal/remote_host_widget.go b/internal/remote_host_widget.go index 0ad4498..df782f2 100644 --- a/internal/remote_host_widget.go +++ b/internal/remote_host_widget.go @@ -22,6 +22,7 @@ const ( rhBarMemory = "rh.bar_memory" rhBarRates = "rh.bar_rates" rhTableDisk = "rh.table_disk" + rhTable = "rh.table" ) type remoteHostWidget struct { @@ -68,6 +69,8 @@ func (ms *remoteHostWidget) CreateWidgets(widget Widget, tui *Tui) (f func() err f, err = ms.barRates(widget) case rhTableDisk: f, err = ms.tableDisk(widget) + case rhTable: + f, err = ms.table(widget) default: return nil, errors.Errorf("can't find the widget %s", widget.Name) } @@ -348,5 +351,37 @@ func (ms *remoteHostWidget) tableDisk(widget Widget) (f func() error, err error) return } -// func (ms *monitorServerWidget) table(widget Widget, firstHeader string) (f func() error, err error) { -// } +func (ms *remoteHostWidget) table(widget Widget) (f func() error, err error) { + title := fmt.Sprintf(" Table ") + if _, ok := widget.Options[optionTitle]; ok { + title = widget.Options[optionTitle] + } + + // cmd := "/bin/df -x devtmpfs -x tmpfs -x debugfs | tail -n +2" + cmd := "/bin/df -x devtmpfs -x tmpfs -x debugfs | sed -n '1!p'" + if _, ok := widget.Options[optionCommand]; ok { + cmd = widget.Options[optionCommand] + } + + headers := []string{"Filesystem", "Size", "Used", "Available", "Use%", "Mount"} + if _, ok := widget.Options[optionHeaders]; ok { + if len(widget.Options[optionHeaders]) > 0 { + headers = strings.Split(strings.TrimSpace(widget.Options[optionHeaders]), ",") + } + } + + d, err := ms.service.Table(cmd, headers) + if err != nil { + return nil, err + } + + data := [][]string{} + data = append(data, headers) + data = append(data, d...) + + f = func() error { + return ms.tui.AddTable(data, title, widget.Options) + } + + return +} diff --git a/internal/widget.go b/internal/widget.go index 0708d2c..3df972a 100644 --- a/internal/widget.go +++ b/internal/widget.go @@ -3,6 +3,9 @@ package internal import "strings" const ( + // Data + optionCommand = "command" + // Widget config options optionTitle = "title" optionTitleColor = "title_color" @@ -41,8 +44,7 @@ const ( // Owner / all optionScope = ownerScope - - ownerScope = "owner" + ownerScope = "owner" ) // A widget is a representation of a set of data in the screen. |