summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormatthieu <matthieu.cneude@gmail.com>2020-05-29 15:07:03 +0200
committermatthieu <matthieu.cneude@gmail.com>2020-05-29 15:07:03 +0200
commit83a87f4654e665dc311c46180f21e2e12e85dfe6 (patch)
tree4281e68eba3c58d6407f229e19e2d2c77dee22e6
parent74c6e4afd6f6a734d9a684f4d4ec223d4d70e01c (diff)
Add possibility to pass any command line or bash script to render it in
your dashboard!!??!!
-rw-r--r--go.mod1
-rw-r--r--go.sum14
-rw-r--r--gokit/cmd.go48
-rw-r--r--internal/platform/remote_host.go56
-rw-r--r--internal/remote_host_widget.go39
-rw-r--r--internal/widget.go6
6 files changed, 132 insertions, 32 deletions
diff --git a/go.mod b/go.mod
index 8a8d20d..825eead 100644
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index 8a69ac9..05a0fa0 100644
--- a/go.sum
+++ b/go.sum
@@ -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.