parent
f95ec898a9
commit
a85697efb5
|
@ -11,6 +11,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
const alphanum string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
const alphanum string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||||
|
@ -122,6 +123,23 @@ func GetTLSConfig(
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SnakeCase converts the given string to snake case following the Golang format:
|
||||||
|
// acronyms are converted to lower-case and preceded by an underscore.
|
||||||
|
func SnakeCase(in string) string {
|
||||||
|
runes := []rune(in)
|
||||||
|
length := len(runes)
|
||||||
|
|
||||||
|
var out []rune
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
|
||||||
|
out = append(out, '_')
|
||||||
|
}
|
||||||
|
out = append(out, unicode.ToLower(runes[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
// Glob will test a string pattern, potentially containing globs, against a
|
// Glob will test a string pattern, potentially containing globs, against a
|
||||||
// subject string. The result is a simple true/false, determining whether or
|
// subject string. The result is a simple true/false, determining whether or
|
||||||
// not the glob pattern matched the subject text.
|
// not the glob pattern matched the subject text.
|
||||||
|
|
|
@ -42,3 +42,32 @@ func TestGlob(t *testing.T) {
|
||||||
testGlobNoMatch(t, pattern, "this_is_a_test")
|
testGlobNoMatch(t, pattern, "this_is_a_test")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SnakeTest struct {
|
||||||
|
input string
|
||||||
|
output string
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []SnakeTest{
|
||||||
|
{"a", "a"},
|
||||||
|
{"snake", "snake"},
|
||||||
|
{"A", "a"},
|
||||||
|
{"ID", "id"},
|
||||||
|
{"MOTD", "motd"},
|
||||||
|
{"Snake", "snake"},
|
||||||
|
{"SnakeTest", "snake_test"},
|
||||||
|
{"APIResponse", "api_response"},
|
||||||
|
{"SnakeID", "snake_id"},
|
||||||
|
{"SnakeIDGoogle", "snake_id_google"},
|
||||||
|
{"LinuxMOTD", "linux_motd"},
|
||||||
|
{"OMGWTFBBQ", "omgwtfbbq"},
|
||||||
|
{"omg_wtf_bbq", "omg_wtf_bbq"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSnakeCase(t *testing.T) {
|
||||||
|
for _, test := range tests {
|
||||||
|
if SnakeCase(test.input) != test.output {
|
||||||
|
t.Errorf(`SnakeCase("%s"), wanted "%s", got \%s"`, test.input, test.output, SnakeCase(test.input))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,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/ipmi_sensor"
|
||||||
_ "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"
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
# 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: `name`, `server`, `unit`
|
||||||
|
* 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,server=10.20.2.203,unit=degrees_c,name=ambient_temp status=1i,value=20 1458488465012559455
|
||||||
|
> ipmi_sensor,server=10.20.2.203,unit=feet,name=altitude status=1i,value=80 1458488465012688613
|
||||||
|
> ipmi_sensor,server=10.20.2.203,unit=watts,name=avg_power status=1i,value=220 1458488465012776511
|
||||||
|
> ipmi_sensor,server=10.20.2.203,unit=volts,name=planar_3.3v status=1i,value=3.28 1458488465012861875
|
||||||
|
> ipmi_sensor,server=10.20.2.203,unit=volts,name=planar_vbat status=1i,value=3.04 1458488465013072508
|
||||||
|
> ipmi_sensor,server=10.20.2.203,unit=rpm,name=fan_1a_tach status=1i,value=2610 1458488465013137932
|
||||||
|
> ipmi_sensor,server=10.20.2.203,unit=rpm,name=fan_1b_tach status=1i,value=1775 1458488465013279896
|
||||||
|
```
|
|
@ -1,5 +1,4 @@
|
||||||
// command
|
package ipmi_sensor
|
||||||
package ipmi
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
|
@ -1,5 +1,4 @@
|
||||||
// connection
|
package ipmi_sensor
|
||||||
package ipmi
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,5 +1,4 @@
|
||||||
// ipmi
|
package ipmi_sensor
|
||||||
package ipmi
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -60,12 +59,20 @@ func (m *Ipmi) gatherServer(serv string, acc telegraf.Accumulator) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// each line will look something like
|
||||||
|
// Planar VBAT | 3.05 Volts | ok
|
||||||
lines := strings.Split(res, "\n")
|
lines := strings.Split(res, "\n")
|
||||||
|
|
||||||
for i := 0; i < len(lines); i++ {
|
for i := 0; i < len(lines); i++ {
|
||||||
vals := strings.Split(lines[i], "|")
|
vals := strings.Split(lines[i], "|")
|
||||||
if len(vals) == 3 {
|
if len(vals) != 3 {
|
||||||
tags := map[string]string{"server": conn.Hostname, "name": trim(vals[0])}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := map[string]string{
|
||||||
|
"server": conn.Hostname,
|
||||||
|
"name": transform(vals[0]),
|
||||||
|
}
|
||||||
|
|
||||||
fields := make(map[string]interface{})
|
fields := make(map[string]interface{})
|
||||||
if strings.EqualFold("ok", trim(vals[2])) {
|
if strings.EqualFold("ok", trim(vals[2])) {
|
||||||
fields["status"] = 1
|
fields["status"] = 1
|
||||||
|
@ -76,15 +83,18 @@ func (m *Ipmi) gatherServer(serv string, acc telegraf.Accumulator) error {
|
||||||
val1 := trim(vals[1])
|
val1 := trim(vals[1])
|
||||||
|
|
||||||
if strings.Index(val1, " ") > 0 {
|
if strings.Index(val1, " ") > 0 {
|
||||||
val := strings.Split(val1, " ")[0]
|
// split middle column into value and unit
|
||||||
fields["value"] = Atofloat(val)
|
valunit := strings.SplitN(val1, " ", 2)
|
||||||
|
fields["value"] = Atofloat(valunit[0])
|
||||||
|
if len(valunit) > 1 {
|
||||||
|
tags["unit"] = transform(valunit[1])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fields["value"] = 0.0
|
fields["value"] = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.AddFields("ipmi_sensor", fields, tags, time.Now())
|
acc.AddFields("ipmi_sensor", fields, tags, time.Now())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -96,9 +106,9 @@ type Runner interface {
|
||||||
func Atofloat(val string) float64 {
|
func Atofloat(val string) float64 {
|
||||||
f, err := strconv.ParseFloat(val, 64)
|
f, err := strconv.ParseFloat(val, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return float64(0)
|
return 0.0
|
||||||
} else {
|
} else {
|
||||||
return float64(f)
|
return f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,8 +116,14 @@ func trim(s string) string {
|
||||||
return strings.TrimSpace(s)
|
return strings.TrimSpace(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func transform(s string) string {
|
||||||
|
s = trim(s)
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
return strings.Replace(s, " ", "_", -1)
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
inputs.Add("ipmi", func() telegraf.Input {
|
inputs.Add("ipmi_sensor", func() telegraf.Input {
|
||||||
return &Ipmi{}
|
return &Ipmi{}
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
// ipmi_test
|
package ipmi_sensor
|
||||||
package ipmi
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -179,6 +178,93 @@ func TestIpmi(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, acc.NFields(), 266, "non-numeric measurements should be ignored")
|
assert.Equal(t, acc.NFields(), 266, "non-numeric measurements should be ignored")
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
fields map[string]interface{}
|
||||||
|
tags map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": float64(20),
|
||||||
|
"status": int(1),
|
||||||
|
},
|
||||||
|
map[string]string{
|
||||||
|
"name": "ambient_temp",
|
||||||
|
"server": "192.168.1.1",
|
||||||
|
"unit": "degrees_c",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": float64(80),
|
||||||
|
"status": int(1),
|
||||||
|
},
|
||||||
|
map[string]string{
|
||||||
|
"name": "altitude",
|
||||||
|
"server": "192.168.1.1",
|
||||||
|
"unit": "feet",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": float64(210),
|
||||||
|
"status": int(1),
|
||||||
|
},
|
||||||
|
map[string]string{
|
||||||
|
"name": "avg_power",
|
||||||
|
"server": "192.168.1.1",
|
||||||
|
"unit": "watts",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": float64(4.9),
|
||||||
|
"status": int(1),
|
||||||
|
},
|
||||||
|
map[string]string{
|
||||||
|
"name": "planar_5v",
|
||||||
|
"server": "192.168.1.1",
|
||||||
|
"unit": "volts",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": float64(3.05),
|
||||||
|
"status": int(1),
|
||||||
|
},
|
||||||
|
map[string]string{
|
||||||
|
"name": "planar_vbat",
|
||||||
|
"server": "192.168.1.1",
|
||||||
|
"unit": "volts",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": float64(2610),
|
||||||
|
"status": int(1),
|
||||||
|
},
|
||||||
|
map[string]string{
|
||||||
|
"name": "fan_1a_tach",
|
||||||
|
"server": "192.168.1.1",
|
||||||
|
"unit": "rpm",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"value": float64(1775),
|
||||||
|
"status": int(1),
|
||||||
|
},
|
||||||
|
map[string]string{
|
||||||
|
"name": "fan_1b_tach",
|
||||||
|
"server": "192.168.1.1",
|
||||||
|
"unit": "rpm",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
acc.AssertContainsTaggedFields(t, "ipmi_sensor", test.fields, test.tags)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIpmiConnection(t *testing.T) {
|
func TestIpmiConnection(t *testing.T) {
|
Loading…
Reference in New Issue