Add the ipmi plugin
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/haproxy"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/httpjson"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/influxdb"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/ipmi"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/jolokia"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/kafka_consumer"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/leofs"
|
||||
|
||||
62
plugins/inputs/ipmi/command.go
Normal file
62
plugins/inputs/ipmi/command.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// command
|
||||
package ipmi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IpmiCommand struct {
|
||||
*Connection
|
||||
}
|
||||
|
||||
func (t *IpmiCommand) options() []string {
|
||||
intf := t.Interface
|
||||
if intf == "" {
|
||||
intf = "lanplus"
|
||||
}
|
||||
|
||||
options := []string{
|
||||
"-H", t.Hostname,
|
||||
"-U", t.Username,
|
||||
"-P", t.Password,
|
||||
"-I", intf,
|
||||
}
|
||||
|
||||
if t.Port != 0 {
|
||||
options = append(options, "-p", strconv.Itoa(t.Port))
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func (t *IpmiCommand) cmd(args ...string) *exec.Cmd {
|
||||
path := t.Path
|
||||
opts := append(t.options(), args...)
|
||||
|
||||
if path == "" {
|
||||
path = "ipmitool"
|
||||
}
|
||||
|
||||
return exec.Command(path, opts...)
|
||||
|
||||
}
|
||||
|
||||
func (t *IpmiCommand) Run(args ...string) (string, error) {
|
||||
cmd := t.cmd(args...)
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("run %s %s: %s (%s)",
|
||||
cmd.Path, strings.Join(cmd.Args, " "), stderr.String(), err)
|
||||
}
|
||||
|
||||
return stdout.String(), err
|
||||
}
|
||||
69
plugins/inputs/ipmi/connection.go
Normal file
69
plugins/inputs/ipmi/connection.go
Normal file
@@ -0,0 +1,69 @@
|
||||
// connection
|
||||
package ipmi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Connection properties for a Client
|
||||
type Connection struct {
|
||||
Hostname string
|
||||
Username string
|
||||
Password string
|
||||
Path string
|
||||
Port int
|
||||
Interface string
|
||||
}
|
||||
|
||||
func NewConnection(server string) *Connection {
|
||||
conn := &Connection{}
|
||||
inx1 := strings.Index(server, "@")
|
||||
inx2 := strings.Index(server, "(")
|
||||
inx3 := strings.Index(server, ")")
|
||||
|
||||
connstr := server
|
||||
|
||||
if inx1 > 0 {
|
||||
security := server[0:inx1]
|
||||
connstr = server[inx1+1 : len(server)]
|
||||
up := strings.Split(security, ":")
|
||||
conn.Username = up[0]
|
||||
conn.Password = up[1]
|
||||
}
|
||||
|
||||
if inx2 > 0 {
|
||||
inx2 = strings.Index(connstr, "(")
|
||||
inx3 = strings.Index(connstr, ")")
|
||||
|
||||
conn.Interface = connstr[0:inx2]
|
||||
conn.Hostname = connstr[inx2+1 : inx3]
|
||||
}
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
// RemoteIP returns the remote (bmc) IP address of the Connection
|
||||
func (c *Connection) RemoteIP() string {
|
||||
if net.ParseIP(c.Hostname) == nil {
|
||||
addrs, err := net.LookupHost(c.Hostname)
|
||||
if err != nil && len(addrs) > 0 {
|
||||
return addrs[0]
|
||||
}
|
||||
}
|
||||
return c.Hostname
|
||||
}
|
||||
|
||||
// LocalIP returns the local (client) IP address of the Connection
|
||||
func (c *Connection) LocalIP() string {
|
||||
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", c.Hostname, c.Port))
|
||||
if err != nil {
|
||||
// don't bother returning an error, since this value will never
|
||||
// make it to the bmc if we can't connect to it.
|
||||
return c.Hostname
|
||||
}
|
||||
_ = conn.Close()
|
||||
host, _, _ := net.SplitHostPort(conn.LocalAddr().String())
|
||||
return host
|
||||
}
|
||||
119
plugins/inputs/ipmi/ipmi.go
Normal file
119
plugins/inputs/ipmi/ipmi.go
Normal file
@@ -0,0 +1,119 @@
|
||||
// ipmi
|
||||
package ipmi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type Ipmi struct {
|
||||
Servers []string
|
||||
}
|
||||
|
||||
var sampleConfig = `
|
||||
## specify servers via a url matching:
|
||||
## [username[:password]@][protocol[(address)]]
|
||||
## e.g.
|
||||
## root:passwd@lan(127.0.0.1)
|
||||
##
|
||||
servers = ["USERID:PASSW0RD@lan(192.168.1.1)"]
|
||||
`
|
||||
var localhost = ""
|
||||
|
||||
func (m *Ipmi) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (m *Ipmi) Description() string {
|
||||
return "Read metrics from one or many bare metal servers"
|
||||
}
|
||||
|
||||
func (m *Ipmi) Gather(acc telegraf.Accumulator) error {
|
||||
if len(m.Servers) == 0 {
|
||||
// if we can't get stats in this case, thats fine, don't report
|
||||
// an error.
|
||||
m.gatherServer(localhost, acc)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, serv := range m.Servers {
|
||||
err := m.gatherServer(serv, acc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Ipmi) gatherServer(serv string, acc telegraf.Accumulator) error {
|
||||
conn := NewConnection(serv)
|
||||
|
||||
tool := &IpmiCommand{conn}
|
||||
res, err := tool.Run("sdr")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lines := strings.Split(res, "\n")
|
||||
|
||||
for i := 0; i < len(lines); i++ {
|
||||
vals := strings.Split(lines[i], "|")
|
||||
if len(vals) == 3 {
|
||||
tags := map[string]string{"host": conn.Hostname, "inst": trim(vals[0])}
|
||||
fields := make(map[string]interface{})
|
||||
if strings.EqualFold("ok", trim(vals[2])) {
|
||||
fields["status"] = 1
|
||||
} else {
|
||||
fields["status"] = 0
|
||||
}
|
||||
|
||||
val1 := trim(vals[1])
|
||||
|
||||
if strings.Index(val1, " ") > 0 {
|
||||
val := strings.Split(val1, " ")[0]
|
||||
fields["value"] = Atofloat(val)
|
||||
} else {
|
||||
fields["value"] = 0.0
|
||||
}
|
||||
|
||||
acc.AddFields("ipmi_sensor", fields, tags, time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Atofloat4(val float64) float64 {
|
||||
str := fmt.Sprintf("%.4f", val)
|
||||
return Atofloat(str)
|
||||
}
|
||||
|
||||
func Atofloat2(val float64) float64 {
|
||||
str := fmt.Sprintf("%.2f", val)
|
||||
return Atofloat(str)
|
||||
}
|
||||
|
||||
func Atofloat(val string) float64 {
|
||||
f, err := strconv.ParseFloat(val, 64)
|
||||
if err != nil {
|
||||
return float64(0)
|
||||
} else {
|
||||
return float64(f)
|
||||
}
|
||||
}
|
||||
|
||||
func trim(s string) string {
|
||||
return strings.TrimSpace(s)
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("ipmi", func() telegraf.Input {
|
||||
return &Ipmi{}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user