From e3e6fa4f1dbe16f1af7688f1ea1457892aa382e6 Mon Sep 17 00:00:00 2001 From: Lukasz Jagiello Date: Wed, 25 May 2016 23:49:42 +0000 Subject: [PATCH] Sudo support for ceph/varnish plugin In many default installations ceph and varnish binaries require root permissions or specific user permissions to actually gather metrics. Although it's possible to instrumented system configuration to either run telegraf with root privileges or share the same user/permissions as measured software it's not a default setup. In my opinion ability to run binary with `sudo` makes entire setup simpler without additional interaction. My changes allow to use configuration like: ``` binary = "/usr/bin/sudo /usr/bin/varnishstat" ceph_binary = "/usr/bin/sudo /usr/bin/ceph" ``` With a proper sudo configuration it will simplify amount of changes needed to collect metrics. I've also changed type of varnish metrics. It was `int` but in varnish source code we can find all metrics are actually uint64 (https://github.com/varnishcache/varnish-cache/blob/master/include/tbl/vsc_f_main.h) I hit that issue with some metrics: ``` ~# varnishstat -1 | grep -i MAIN.n_objectcore MAIN.n_objectcore 18446744073709550877 . objectcore structs made ``` --- plugins/inputs/ceph/ceph.go | 13 +++++++++++-- plugins/inputs/varnish/varnish.go | 13 ++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/plugins/inputs/ceph/ceph.go b/plugins/inputs/ceph/ceph.go index d8ebf5017..2e1d65e38 100644 --- a/plugins/inputs/ceph/ceph.go +++ b/plugins/inputs/ceph/ceph.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/gonuts/go-shellquote" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/plugins/inputs" "io/ioutil" @@ -109,7 +110,13 @@ func init() { } var perfDump = func(binary string, socket *socket) (string, error) { + split_cmd, err := shellquote.Split(binary) + if err != nil || len(split_cmd) == 0 { + return "", fmt.Errorf("exec: unable to parse command, %s", err) + } + cmdArgs := []string{"--admin-daemon", socket.socket} + if socket.sockType == typeOsd { cmdArgs = append(cmdArgs, "perf", "dump") } else if socket.sockType == typeMon { @@ -118,10 +125,12 @@ var perfDump = func(binary string, socket *socket) (string, error) { return "", fmt.Errorf("ignoring unknown socket type: %s", socket.sockType) } - cmd := exec.Command(binary, cmdArgs...) + split_cmd = append(split_cmd, cmdArgs...) + + cmd := exec.Command(split_cmd[0], split_cmd[1:]...) var out bytes.Buffer cmd.Stdout = &out - err := cmd.Run() + err = cmd.Run() if err != nil { return "", fmt.Errorf("error running ceph dump: %s", err) } diff --git a/plugins/inputs/varnish/varnish.go b/plugins/inputs/varnish/varnish.go index 0834a6e9d..4bc58c156 100644 --- a/plugins/inputs/varnish/varnish.go +++ b/plugins/inputs/varnish/varnish.go @@ -11,6 +11,8 @@ import ( "strconv" "strings" + "github.com/gonuts/go-shellquote" + "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/plugins/inputs" @@ -84,12 +86,17 @@ func (s *Varnish) statsFilter() func(string) bool { // Shell out to varnish_stat and return the output var varnishStat = func(cmdName string) (*bytes.Buffer, error) { + split_cmd, err := shellquote.Split(cmdName) + if err != nil || len(split_cmd) == 0 { + return nil, fmt.Errorf("exec: unable to parse command, %s", err) + } cmdArgs := []string{"-1"} + split_cmd = append(split_cmd, cmdArgs...) - cmd := exec.Command(cmdName, cmdArgs...) + cmd := exec.Command(split_cmd[0], split_cmd[1:]...) var out bytes.Buffer cmd.Stdout = &out - err := internal.RunTimeout(cmd, time.Millisecond*200) + err = internal.RunTimeout(cmd, time.Millisecond*200) if err != nil { return &out, fmt.Errorf("error running varnishstat: %s", err) } @@ -138,7 +145,7 @@ func (s *Varnish) Gather(acc telegraf.Accumulator) error { sectionMap[section] = make(map[string]interface{}) } - sectionMap[section][field], err = strconv.Atoi(value) + sectionMap[section][field], err = strconv.ParseUint(value, 10, 64) if err != nil { fmt.Fprintf(os.Stderr, "Expected a numeric value for %s = %v\n", stat, value)