-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
482 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Telegraf ipmi plugin | ||
|
||
Get bare metal metrics using the command line utility `ipmitool` | ||
|
||
see ipmitool(https://sourceforge.net/projects/ipmitool/files/ipmitool/) | ||
|
||
The plugin will use the following command to collect remote host sensor stats: | ||
|
||
ipmitool -I lan -H 192.168.1.1 -U USERID -P PASSW0RD sdr | ||
|
||
## Measurements | ||
|
||
- ipmi_sensor: | ||
|
||
* Tags: `server`,`host` | ||
* Fields: | ||
- status | ||
- value | ||
|
||
## Configuration | ||
|
||
```toml | ||
[[inputs.ipmi]] | ||
## specify servers via a url matching: | ||
## [username[:password]@][protocol[(address)]] | ||
## e.g. | ||
## root:passwd@lan(127.0.0.1) | ||
## | ||
servers = ["USERID:PASSW0RD@lan(10.20.2.203)"] | ||
``` | ||
|
||
## Output | ||
|
||
> ipmi_sensor,host=10.20.2.203,inst=Ambient\ Temp status=1i,value=20 1458488465012559455 | ||
> ipmi_sensor,host=10.20.2.203,inst=Altitude status=1i,value=80 1458488465012688613 | ||
> ipmi_sensor,host=10.20.2.203,inst=Avg\ Power status=1i,value=220 1458488465012776511 | ||
> ipmi_sensor,host=10.20.2.203,inst=Planar\ 3.3V status=1i,value=3.28 1458488465012861875 | ||
> ipmi_sensor,host=10.20.2.203,inst=Planar\ 5V status=1i,value=4.9 1458488465012944188 | ||
> ipmi_sensor,host=10.20.2.203,inst=Planar\ 12V status=1i,value=12.04 1458488465013008485 | ||
> ipmi_sensor,host=10.20.2.203,inst=Planar\ VBAT status=1i,value=3.04 1458488465013072508 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 1A\ Tach status=1i,value=2610 1458488465013137932 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 1B\ Tach status=1i,value=1775 1458488465013279896 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 2A\ Tach status=1i,value=1972 1458488465013358177 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 2B\ Tach status=1i,value=1275 1458488465013434023 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 3A\ Tach status=1i,value=2929 1458488465013514567 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 3B\ Tach status=1i,value=2125 1458488465013582616 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 1 status=1i,value=0 1458488465013643746 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 2 status=1i,value=0 1458488465013714887 | ||
> ipmi_sensor,host=10.20.2.203,inst=Fan\ 3 status=1i,value=0 1458488465013861854 | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// command | ||
package ipmi | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os/exec" | ||
"strings" | ||
) | ||
|
||
type CommandRunner struct{} | ||
|
||
func (t CommandRunner) cmd(conn *Connection, args ...string) *exec.Cmd { | ||
path := conn.Path | ||
opts := append(conn.options(), args...) | ||
|
||
if path == "" { | ||
path = "ipmitool" | ||
} | ||
|
||
return exec.Command(path, opts...) | ||
|
||
} | ||
|
||
func (t CommandRunner) Run(conn *Connection, args ...string) (string, error) { | ||
cmd := t.cmd(conn, 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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// connection | ||
package ipmi | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"strconv" | ||
"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 | ||
} | ||
|
||
func (t *Connection) options() []string { | ||
intf := t.Interface | ||
if intf == "" { | ||
intf = "lan" | ||
} | ||
|
||
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 | ||
} | ||
|
||
// 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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// ipmi | ||
package ipmi | ||
|
||
import ( | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/plugins/inputs" | ||
) | ||
|
||
type Ipmi struct { | ||
Servers []string | ||
runner Runner | ||
} | ||
|
||
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)"] | ||
` | ||
|
||
func NewIpmi() *Ipmi { | ||
return &Ipmi{ | ||
runner: CommandRunner{}, | ||
} | ||
} | ||
|
||
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 m.runner == nil { | ||
m.runner = CommandRunner{} | ||
} | ||
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) | ||
|
||
res, err := m.runner.Run(conn, "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{"server": conn.Hostname, "name": 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 | ||
} | ||
|
||
type Runner interface { | ||
Run(conn *Connection, args ...string) (string, error) | ||
} | ||
|
||
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{} | ||
}) | ||
} |
Oops, something went wrong.