Skip to content

Commit

Permalink
Convert ipmi stats/tags to underscore and lowercase
Browse files Browse the repository at this point in the history
closes #888
  • Loading branch information
sparrc committed Mar 29, 2016
1 parent d055d7f commit 21ece2d
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 79 deletions.
18 changes: 18 additions & 0 deletions internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os"
"strings"
"time"
"unicode"
)

const alphanum string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
Expand Down Expand Up @@ -122,6 +123,23 @@ func GetTLSConfig(
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
// subject string. The result is a simple true/false, determining whether or
// not the glob pattern matched the subject text.
Expand Down
29 changes: 29 additions & 0 deletions internal/internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,32 @@ func TestGlob(t *testing.T) {
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))
}
}
}
2 changes: 1 addition & 1 deletion plugins/inputs/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,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/ipmi_sensor"
_ "github.com/influxdata/telegraf/plugins/inputs/jolokia"
_ "github.com/influxdata/telegraf/plugins/inputs/kafka_consumer"
_ "github.com/influxdata/telegraf/plugins/inputs/leofs"
Expand Down
50 changes: 0 additions & 50 deletions plugins/inputs/ipmi/README.md

This file was deleted.

42 changes: 42 additions & 0 deletions plugins/inputs/ipmi_sensor/README.md
Original file line number Diff line number Diff line change
@@ -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
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// command
package ipmi
package ipmi_sensor

import (
"bytes"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// connection
package ipmi
package ipmi_sensor

import (
"fmt"
Expand Down
60 changes: 38 additions & 22 deletions plugins/inputs/ipmi/ipmi.go → plugins/inputs/ipmi_sensor/ipmi.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ipmi
package ipmi
package ipmi_sensor

import (
"strconv"
Expand Down Expand Up @@ -60,30 +59,41 @@ func (m *Ipmi) gatherServer(serv string, acc telegraf.Accumulator) error {
return err
}

// each line will look something like
// Planar VBAT | 3.05 Volts | ok
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
}
if len(vals) != 3 {
continue
}

val1 := trim(vals[1])
tags := map[string]string{
"server": conn.Hostname,
"name": transform(vals[0]),
}

if strings.Index(val1, " ") > 0 {
val := strings.Split(val1, " ")[0]
fields["value"] = Atofloat(val)
} else {
fields["value"] = 0.0
}
fields := make(map[string]interface{})
if strings.EqualFold("ok", trim(vals[2])) {
fields["status"] = 1
} else {
fields["status"] = 0
}

acc.AddFields("ipmi_sensor", fields, tags, time.Now())
val1 := trim(vals[1])

if strings.Index(val1, " ") > 0 {
// split middle column into value and unit
valunit := strings.SplitN(val1, " ", 2)
fields["value"] = Atofloat(valunit[0])
if len(valunit) > 1 {
tags["unit"] = transform(valunit[1])
}
} else {
fields["value"] = 0.0
}

acc.AddFields("ipmi_sensor", fields, tags, time.Now())
}

return nil
Expand All @@ -96,18 +106,24 @@ type Runner interface {
func Atofloat(val string) float64 {
f, err := strconv.ParseFloat(val, 64)
if err != nil {
return float64(0)
return 0.0
} else {
return float64(f)
return f
}
}

func trim(s string) string {
return strings.TrimSpace(s)
}

func transform(s string) string {
s = trim(s)
s = strings.ToLower(s)
return strings.Replace(s, " ", "_", -1)
}

func init() {
inputs.Add("ipmi", func() telegraf.Input {
inputs.Add("ipmi_sensor", func() telegraf.Input {
return &Ipmi{}
})
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ipmi_test
package ipmi
package ipmi_sensor

import (
"testing"
Expand Down Expand Up @@ -179,6 +178,93 @@ func TestIpmi(t *testing.T) {
require.NoError(t, err)

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) {
Expand Down

0 comments on commit 21ece2d

Please sign in to comment.