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
```
This commit is contained in:
Lukasz Jagiello 2016-05-25 23:49:42 +00:00
parent 3e4a19539a
commit e3e6fa4f1d
No known key found for this signature in database
GPG Key ID: AD709E6DC0024651
2 changed files with 21 additions and 5 deletions

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/gonuts/go-shellquote"
"github.com/influxdata/telegraf" "github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs" "github.com/influxdata/telegraf/plugins/inputs"
"io/ioutil" "io/ioutil"
@ -109,7 +110,13 @@ func init() {
} }
var perfDump = func(binary string, socket *socket) (string, error) { 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} cmdArgs := []string{"--admin-daemon", socket.socket}
if socket.sockType == typeOsd { if socket.sockType == typeOsd {
cmdArgs = append(cmdArgs, "perf", "dump") cmdArgs = append(cmdArgs, "perf", "dump")
} else if socket.sockType == typeMon { } 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) 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 var out bytes.Buffer
cmd.Stdout = &out cmd.Stdout = &out
err := cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
return "", fmt.Errorf("error running ceph dump: %s", err) return "", fmt.Errorf("error running ceph dump: %s", err)
} }

View File

@ -11,6 +11,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/gonuts/go-shellquote"
"github.com/influxdata/telegraf" "github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs" "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 // Shell out to varnish_stat and return the output
var varnishStat = func(cmdName string) (*bytes.Buffer, error) { 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"} 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 var out bytes.Buffer
cmd.Stdout = &out cmd.Stdout = &out
err := internal.RunTimeout(cmd, time.Millisecond*200) err = internal.RunTimeout(cmd, time.Millisecond*200)
if err != nil { if err != nil {
return &out, fmt.Errorf("error running varnishstat: %s", err) 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] = make(map[string]interface{})
} }
sectionMap[section][field], err = strconv.Atoi(value) sectionMap[section][field], err = strconv.ParseUint(value, 10, 64)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Expected a numeric value for %s = %v\n", fmt.Fprintf(os.Stderr, "Expected a numeric value for %s = %v\n",
stat, value) stat, value)