Add the ipmi plugin
This commit is contained in:
parent
530b4f3bee
commit
762b33fe31
|
@ -0,0 +1,106 @@
|
||||||
|
# Telegraf Configuration
|
||||||
|
|
||||||
|
# Telegraf is entirely plugin driven. All metrics are gathered from the
|
||||||
|
# declared inputs, and sent to the declared outputs.
|
||||||
|
|
||||||
|
# Plugins must be declared in here to be active.
|
||||||
|
# To deactivate a plugin, comment out the name and any variables.
|
||||||
|
|
||||||
|
# Use 'telegraf -config telegraf.conf -test' to see what metrics a config
|
||||||
|
# file would generate.
|
||||||
|
|
||||||
|
# Global tags can be specified here in key="value" format.
|
||||||
|
[global_tags]
|
||||||
|
# dc = "us-east-1" # will tag all metrics with dc=us-east-1
|
||||||
|
# rack = "1a"
|
||||||
|
|
||||||
|
# Configuration for telegraf agent
|
||||||
|
[agent]
|
||||||
|
## Default data collection interval for all inputs
|
||||||
|
interval = "10s"
|
||||||
|
## Rounds collection interval to 'interval'
|
||||||
|
## ie, if interval="10s" then always collect on :00, :10, :20, etc.
|
||||||
|
round_interval = true
|
||||||
|
|
||||||
|
## Telegraf will cache metric_buffer_limit metrics for each output, and will
|
||||||
|
## flush this buffer on a successful write.
|
||||||
|
metric_buffer_limit = 1000
|
||||||
|
## Flush the buffer whenever full, regardless of flush_interval.
|
||||||
|
flush_buffer_when_full = true
|
||||||
|
|
||||||
|
## Collection jitter is used to jitter the collection by a random amount.
|
||||||
|
## Each plugin will sleep for a random time within jitter before collecting.
|
||||||
|
## This can be used to avoid many plugins querying things like sysfs at the
|
||||||
|
## same time, which can have a measurable effect on the system.
|
||||||
|
collection_jitter = "0s"
|
||||||
|
|
||||||
|
## Default flushing interval for all outputs. You shouldn't set this below
|
||||||
|
## interval. Maximum flush_interval will be flush_interval + flush_jitter
|
||||||
|
flush_interval = "10s"
|
||||||
|
## Jitter the flush interval by a random amount. This is primarily to avoid
|
||||||
|
## large write spikes for users running a large number of telegraf instances.
|
||||||
|
## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s
|
||||||
|
flush_jitter = "0s"
|
||||||
|
|
||||||
|
## Run telegraf in debug mode
|
||||||
|
debug = false
|
||||||
|
## Run telegraf in quiet mode
|
||||||
|
quiet = false
|
||||||
|
## Override default hostname, if empty use os.Hostname()
|
||||||
|
hostname = ""
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# OUTPUTS:
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Configuration for influxdb server to send metrics to
|
||||||
|
[[outputs.influxdb]]
|
||||||
|
## The full HTTP or UDP endpoint URL for your InfluxDB instance.
|
||||||
|
## Multiple urls can be specified as part of the same cluster,
|
||||||
|
## this means that only ONE of the urls will be written to each interval.
|
||||||
|
# urls = ["udp://localhost:8089"] # UDP endpoint example
|
||||||
|
urls = ["http://localhost:8086"] # required
|
||||||
|
## The target database for metrics (telegraf will create it if not exists).
|
||||||
|
database = "telegraf" # required
|
||||||
|
## Retention policy to write to.
|
||||||
|
retention_policy = "default"
|
||||||
|
## Precision of writes, valid values are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
||||||
|
## note: using "s" precision greatly improves InfluxDB compression.
|
||||||
|
precision = "s"
|
||||||
|
|
||||||
|
## Write timeout (for the InfluxDB client), formatted as a string.
|
||||||
|
## If not provided, will default to 5s. 0s means no timeout (not recommended).
|
||||||
|
timeout = "5s"
|
||||||
|
# username = "telegraf"
|
||||||
|
# password = "metricsmetricsmetricsmetrics"
|
||||||
|
## Set the user agent for HTTP POSTs (can be useful for log differentiation)
|
||||||
|
# user_agent = "telegraf"
|
||||||
|
## Set UDP payload size, defaults to InfluxDB UDP Client default (512 bytes)
|
||||||
|
# udp_payload = 512
|
||||||
|
|
||||||
|
## Optional SSL Config
|
||||||
|
# ssl_ca = "/etc/telegraf/ca.pem"
|
||||||
|
# ssl_cert = "/etc/telegraf/cert.pem"
|
||||||
|
# ssl_key = "/etc/telegraf/key.pem"
|
||||||
|
## Use SSL but skip chain & host verification
|
||||||
|
# insecure_skip_verify = false
|
||||||
|
|
||||||
|
#
|
||||||
|
# INPUTS:
|
||||||
|
#
|
||||||
|
|
||||||
|
# Read metrics from one or many bare metal servers
|
||||||
|
[[inputs.ipmi]]
|
||||||
|
## specify servers via a url matching:
|
||||||
|
## [username[:password]@][protocol[(address)]]
|
||||||
|
## e.g.
|
||||||
|
## root:passwd@tcp(127.0.0.1:3306)
|
||||||
|
##
|
||||||
|
## If no servers are specified, then localhost is used as the host.
|
||||||
|
servers = ["USERID:PASSW0RD@lan(10.20.2.203)"]
|
||||||
|
|
||||||
|
#
|
||||||
|
# SERVICE INPUTS:
|
||||||
|
#
|
Binary file not shown.
Binary file not shown.
|
@ -15,6 +15,7 @@ import (
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/haproxy"
|
_ "github.com/influxdata/telegraf/plugins/inputs/haproxy"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/httpjson"
|
_ "github.com/influxdata/telegraf/plugins/inputs/httpjson"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/influxdb"
|
_ "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/jolokia"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/kafka_consumer"
|
_ "github.com/influxdata/telegraf/plugins/inputs/kafka_consumer"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/leofs"
|
_ "github.com/influxdata/telegraf/plugins/inputs/leofs"
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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{}
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue